harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From le...@apache.org
Subject svn commit: r595523 - in /harmony/enhanced/classlib/trunk/modules/jndi: META-INF/ src/main/java/org/apache/harmony/jndi/provider/ldap/ src/test/java/org/apache/harmony/jndi/provider/ldap/
Date Fri, 16 Nov 2007 02:34:55 GMT
Author: leoli
Date: Thu Nov 15 18:34:54 2007
New Revision: 595523

URL: http://svn.apache.org/viewvc?rev=595523&view=rev
Log:
Apply patch for HARMONY-5126([classlib][jndi][ldap] refactor LdapClient).

Modified:
    harmony/enhanced/classlib/trunk/modules/jndi/META-INF/MANIFEST.MF
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapMessageTest.java

Modified: harmony/enhanced/classlib/trunk/modules/jndi/META-INF/MANIFEST.MF
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/META-INF/MANIFEST.MF?rev=595523&r1=595522&r2=595523&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/META-INF/MANIFEST.MF (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/META-INF/MANIFEST.MF Thu Nov 15 18:34:54
2007
@@ -32,6 +32,8 @@
  javax.accessibility;resolution:=optional,
  javax.net,
  javax.net.ssl,
+ javax.security.auth.callback,
+ javax.security.sasl,
  org.apache.harmony.kernel.vm,
  org.apache.harmony.security.asn1;version="1.0.0",
  org.apache.harmony.security.x509;version="1.0.0",

Modified: 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=595523&r1=595522&r2=595523&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
Thu Nov 15 18:34:54 2007
@@ -43,26 +43,46 @@
  * 
  */
 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;
 
-    /*
+    /**
      * Address of connection
      */
     private String address;
 
+    /**
+     * port of connection
+     */
+    private int port;
+
+    /**
+     * blocked requests list which wait for response
+     */
+    private Hashtable<Integer, Element> requests = new Hashtable<Integer, Element>();
+
+    /**
+     * the max time to wait server response in milli-second
+     */
+    private long MAX_WAIT_TIME = 30 * 1000;
+
+    /**
+     * responsible for dispatching received messages
+     */
+    private Dispatcher dispatcher;
+
     // constructor for test
     public LdapClient() {
         // do nothing
@@ -85,15 +105,151 @@
     public LdapClient(SocketFactory factory, String address, int port)
             throws UnknownHostException, IOException {
         this.address = address;
+        this.port = port;
         socket = factory.createSocket(address, port);
         // FIXME: Use of InputStreamWrap here is to deal with a potential bug of
         // RI.
         in = new InputStreamWrap(socket.getInputStream());
-        // in = socket.getInputStream();
         out = socket.getOutputStream();
+        dispatcher = new Dispatcher();
+        dispatcher.start();
     }
 
     /**
+     * The instance of the class is daemon thread, which read messages from
+     * server and dispatch to corresponding thread.
+     */
+    class Dispatcher extends Thread {
+
+        private boolean isStopped = false;
+
+        public Dispatcher() {
+            /**
+             * must be daemon thread, otherwrise can't destory by gc
+             */
+            setDaemon(true);
+        }
+
+        public boolean isStopped() {
+            return isStopped;
+        }
+
+        public void setStopped(boolean isStopped) {
+            this.isStopped = isStopped;
+        }
+
+        @Override
+        public void run() {
+            while (!isStopped) {
+                try {
+                    // set response op to null, load later
+                    LdapMessage response = new LdapMessage(null) {
+
+                        /**
+                         * Dispatcher can't know which response operation should
+                         * be used until messageId had determined.
+                         * 
+                         * @return response according messageId
+                         */
+                        @Override
+                        public ASN1Decodable getResponseOp() {
+                            // responseOp has been load, just return it
+                            if (super.getResponseOp() != null) {
+                                return super.getResponseOp();
+                            }
+
+                            int messageId = getMessageId();
+
+                            // Unsolicited Notification
+                            if (messageId == 0) {
+                                // TODO return instance of
+                                // UnsolicitedNotificationImpl
+                            }
+
+                            // get response operation according messageId
+                            Element element = requests.get(Integer
+                                    .valueOf(messageId));
+                            if (element != null) {
+                                return element.response.getResponseOp();
+                            }
+
+                            /*
+                             * FIXME: if messageId not find in request list,
+                             * what should we do?
+                             */
+                            return null;
+                        }
+                    };
+
+                    Exception ex = null;
+                    /**
+                     * TODO read message data by ourselves then decode, this
+                     * would be robust
+                     */
+                    try {
+                        // read next message
+                        response.decode(in);
+                    } catch (IOException e) {
+                        // may socket has problem or decode occurs error
+                        ex = e;
+                    } catch (RuntimeException e) {
+                        // may socket has problem or decode occurs error
+                        ex = e;
+                    }
+
+                    processResponse(response, ex);
+
+                } catch (Exception e) {
+                    // may never reach
+                    e.printStackTrace();
+                }
+            }
+
+        }
+
+        private void processResponse(LdapMessage response, Exception ex) {
+            // unsolicited notification
+            if (response.getMessageId() == 0) {
+                // TODO notify unsolicited listeners
+                return;
+            }
+
+            Element element = requests.get(Integer.valueOf(response
+                    .getMessageId()));
+
+            if (element != null) {
+                element.response = response;
+                element.ex = ex;
+                // persistent search response
+                if (element.lock == null) {
+
+                    // TODO notify persistent search listeners
+
+                } else {
+                    /*
+                     * notify the thread which send request and wait for
+                     * response
+                     */
+                    synchronized (element.lock) {
+                        element.lock.notify();
+                    }
+                } // end of if (element.lock == null) else
+            } // end of if (element != null)
+
+            else if (ex != null) {
+                /*
+                 * may asn1 decode error or socket problem, can get message id,
+                 * so couldn't know which thread should be notified
+                 */
+                // FIXME: any better way?
+                close();
+            }
+            // FIXME message id not found and no exception, what shoud we do?
+
+        } // end of processResponse
+    } // Dispatcher
+
+    /**
      * Carry out the ldap operation encapsulated in operation with controls.
      * 
      * @param operation
@@ -126,18 +282,102 @@
     public LdapMessage doOperation(int opIndex, ASN1Encodable request,
             ASN1Decodable response, Control[] controls) throws IOException {
 
+        if (opIndex == LdapASN1Constant.OP_SEARCH_REQUEST) {
+            return doSearchOperation(request, response, controls);
+        }
+
         LdapMessage requestMsg = new LdapMessage(opIndex, request, controls);
-        out.write(requestMsg.encode());
-        out.flush();
-        LdapMessage responseMsg = new LdapMessage(response);
-        responseMsg.decode(in);
 
-        if (opIndex == LdapASN1Constant.OP_SEARCH_REQUEST
-                && responseMsg.getOperationIndex() != LdapASN1Constant.OP_SEARCH_RESULT_DONE)
{
-            responseMsg = new LdapMessage(response);
-            responseMsg.decode(in);
+        Integer messageID = Integer.valueOf(requestMsg.getMessageId());
+
+        Object lock = new Object();
+        requests.put(messageID, new Element(lock, new LdapMessage(response)));
+
+        try {
+            out.write(requestMsg.encode());
+            out.flush();
+            return waitResponse(messageID, lock);
+
+        } finally {
+            // remove request from list
+            requests.remove(messageID);
         }
-        return responseMsg;
+
+    }
+
+    /**
+     * Block the current thread until get response from server or occurs error
+     * 
+     * @param messageID
+     *            id of request message, is same as id of response message
+     * @param response
+     *            decoder of the response
+     * @return response message, may not be null
+     * 
+     * @throws Exception
+     */
+    private LdapMessage waitResponse(Integer messageID, Object lock)
+            throws IOException {
+
+        synchronized (lock) {
+            try {
+                lock.wait(MAX_WAIT_TIME);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+
+        Element element = requests.get(messageID);
+
+        // wait time out
+        if (element.response.getMessageId() != messageID.intValue()) {
+            // ldap.31=Read LDAP response message time out
+            throw new IOException(Messages.getString("ldap.31")); //$NON-NLS-1$
+        }
+
+        // error occurs when read response
+        if (element.ex != null) {
+            // socket is not connected
+            if (!socket.isConnected()) {
+                close();
+            }
+            // element.ex must be one of IOException or RuntimeException
+            if (element.ex instanceof IOException) {
+                throw (IOException) element.ex;
+            }
+
+            throw (RuntimeException) element.ex;
+        }
+
+        return element.response;
+
+    }
+
+    private LdapMessage doSearchOperation(ASN1Encodable request,
+            ASN1Decodable response, Control[] controls) throws IOException {
+        LdapMessage requestMsg = new LdapMessage(
+                LdapASN1Constant.OP_SEARCH_REQUEST, request, controls);
+
+        Integer messageID = Integer.valueOf(requestMsg.getMessageId());
+
+        Object lock = new Object();
+        requests.put(messageID, new Element(lock, new LdapMessage(response)));
+
+        try {
+            out.write(requestMsg.encode());
+            out.flush();
+            LdapMessage responseMsg = waitResponse(messageID, lock);
+
+            while (responseMsg.getOperationIndex() != LdapASN1Constant.OP_SEARCH_RESULT_DONE)
{
+                responseMsg = waitResponse(messageID, lock);
+            }
+
+            return responseMsg;
+        } finally {
+            // remove request from list
+            requests.remove(messageID);
+        }
+
     }
 
     public void abandon(final int messageId, Control[] controls)
@@ -159,8 +399,50 @@
         out.flush();
     }
 
-    public void close() throws IOException {
-        socket.close();
+    /**
+     * Close network connection, stop dispather thread, and release all other
+     * resources
+     * 
+     * NOTE: invoke this method should be careful when this
+     * <code>LdapClient</code> instance is shared by multi
+     * <code>LdapContext</code>
+     * 
+     */
+    public void close() {
+        // close socket
+        if (socket != null) {
+            try {
+                socket.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+
+        socket = null;
+        in = null;
+        out = null;
+
+        // try to stop dispather
+        if (dispatcher != null) {
+            dispatcher.setStopped(true);
+            dispatcher.interrupt();
+        }
+
+        // notify all blocked thread
+        if (requests != null) {
+            for (Element element : requests.values()) {
+                if (element.lock != null) {
+                    synchronized (element.lock) {
+                        element.lock.notify();
+                    }
+                } else {
+                    // TODO notify persistent search listeners
+                }
+            }
+            requests.clear();
+            requests = null;
+        }
+
     }
 
     /**
@@ -234,6 +516,22 @@
         return cls;
     }
 
+    /**
+     * struct for holding necessary info to add to requests list
+     */
+    static class Element {
+        Object lock;
+
+        LdapMessage response;
+
+        Exception ex;
+
+        public Element(Object lock, LdapMessage response) {
+            this.lock = lock;
+            this.response = response;
+        }
+    }
+
     // TODO: This class is used to deal with a potential bug of RI, may be
     // removed in the future.
     /**
@@ -304,5 +602,14 @@
 
     public String getAddress() {
         return address;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    protected void finalize() {
+        close();
     }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java?rev=595523&r1=595522&r2=595523&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
Thu Nov 15 18:34:54 2007
@@ -160,6 +160,12 @@
 
         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) {
@@ -207,4 +213,9 @@
     public int getOperationIndex() {
         return opIndex;
     }
+
+    public ASN1Decodable getResponseOp() {
+        return responseOp;
+    }
+
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapMessageTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapMessageTest.java?rev=595523&r1=595522&r2=595523&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapMessageTest.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapMessageTest.java
Thu Nov 15 18:34:54 2007
@@ -72,6 +72,14 @@
 
     }
 
+    public void test_constructor() {
+        LdapMessage message = new LdapMessage(null);
+        assertNull(message.getControls());
+        assertNull(message.getResponseOp());
+        assertEquals(-1, message.getMessageId());
+        assertEquals(-1, message.getOperationIndex());
+    }
+    
     public void test_encodeValues_$LObject() {
         LdapMessage message = new LdapMessage(
                 LdapASN1Constant.OP_ABANDON_REQUEST, new MockAbandonRequest(1),



Mime
View raw message