diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnSetupMgr.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnSetupMgr.java index df14dfdbfbce..3cad0bb677b1 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnSetupMgr.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnSetupMgr.java @@ -128,6 +128,12 @@ class LDAPConnSetupMgr implements Cloneable, java.io.Serializable { */ private transient int m_attemptCnt = 0; + /** + * Connection IDs for ldap trace messages + */ + private static int m_nextId; + private int m_id; + /** * Constructor * @param host list of host names to which to connect @@ -140,6 +146,7 @@ class LDAPConnSetupMgr implements Cloneable, java.io.Serializable { m_dsList[i] = new ServerEntry(hosts[i], ports[i], NEVER_USED); } m_factory = factory; + m_id = m_nextId++; } /** @@ -509,6 +516,15 @@ class LDAPConnSetupMgr implements Cloneable, java.io.Serializable { return str; } + int getID() { + return m_id; + } + + String getLDAPUrl() { + return ((m_factory == null) ? "ldap" : "ldaps") + + "://" + getHost() + ":" + getPort(); + } + public Object clone() { try { LDAPConnSetupMgr cloneMgr = (LDAPConnSetupMgr) super.clone(); diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnThread.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnThread.java index 57352bd1b8ef..c4c333af1901 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnThread.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnThread.java @@ -28,6 +28,7 @@ import netscape.ldap.ber.stream.*; import netscape.ldap.util.*; import java.io.*; import java.net.*; +import java.text.SimpleDateFormat; /** * Multiple LDAPConnection clones can share a single physical connection, @@ -54,6 +55,7 @@ class LDAPConnThread extends Thread { * Constants */ private final static int MAXMSGID = Integer.MAX_VALUE; + private final static int BACKLOG_CHKCNT = 50; /** * Internal variables @@ -72,7 +74,12 @@ class LDAPConnThread extends Thread { transient Object m_sendRequestLock = new Object(); transient LDAPConnSetupMgr m_connMgr = null; transient Object m_traceOutput = null; + transient private int m_backlogCheckCounter = BACKLOG_CHKCNT; + + // Time Stemp format Hour(0-23):Minute:Second.Milliseconds used for trace msgs + static SimpleDateFormat m_timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); + /** * Constructs a connection thread that maintains connection to the * LDAP server. @@ -89,7 +96,7 @@ class LDAPConnThread extends Thread { m_socket = connMgr.getSocket(); setCache( cache ); setTraceOutput(traceOutput); - + setDaemon(true); try { @@ -109,6 +116,13 @@ class LDAPConnThread extends Thread { throw new LDAPException ( "failed to connect to server " + m_connMgr.getHost(), LDAPException.CONNECT_ERROR ); } + + if (traceOutput != null) { + StringBuffer sb = new StringBuffer(" connected to "); + sb.append(m_connMgr.getLDAPUrl()); + logTraceMessage(sb); + } + start(); /* start the thread */ } @@ -142,20 +156,27 @@ class LDAPConnThread extends Thread { } } - void logLDAPMessage(LDAPMessage msg) { + void logTraceMessage(StringBuffer msg) { + + String timeStamp = m_timeFormat.format(new Date()); + StringBuffer sb = new StringBuffer(timeStamp); + sb.append(" ldc="); + sb.append(m_connMgr.getID()); + synchronized( m_sendRequestLock ) { if (m_traceOutput instanceof PrintWriter) { PrintWriter traceOutput = (PrintWriter)m_traceOutput; - traceOutput.println(msg.toTraceString()); + traceOutput.print(sb); // header + traceOutput.println(msg); traceOutput.flush(); } else if (m_traceOutput instanceof LDAPTraceWriter) { - ((LDAPTraceWriter)m_traceOutput).write(msg.toTraceString()); + sb.append(msg); + ((LDAPTraceWriter)m_traceOutput).write(sb.toString()); } } } - /** * Set the cache to use for searches. * @param cache The cache to use for searches; null for no cache @@ -186,10 +207,10 @@ class LDAPConnThread extends Thread { void sendRequest (LDAPConnection conn, JDAPProtocolOp request, LDAPMessageQueue toNotify, LDAPConstraints cons) throws LDAPException { - if (m_serverOutput == null) + if (!m_doRun) { throw new LDAPException ( "not connected to a server", LDAPException.SERVER_DOWN ); - + } LDAPMessage msg = new LDAPMessage(allocateId(), request, cons.getServerControls()); @@ -208,7 +229,7 @@ class LDAPConnThread extends Thread { synchronized( m_sendRequestLock ) { try { if (m_traceOutput != null) { - logLDAPMessage(msg); + logTraceMessage(msg.toTraceString()); } msg.write (m_serverOutput); m_serverOutput.flush (); @@ -227,10 +248,14 @@ class LDAPConnThread extends Thread { m_registered.addElement(conn); } - synchronized int getClientCount() { + int getClientCount() { return m_registered.size(); } + boolean isRunning() { + return m_doRun; + } + /** * De-Register with this connection thread. If all the connection * is deregistered. Then, this thread should be killed. @@ -240,14 +265,15 @@ class LDAPConnThread extends Thread { m_registered.removeElement(conn); if (m_registered.size() == 0) { try { - - m_doRun =false; - + if (!m_disconnected) { LDAPSearchConstraints cons = conn.getSearchConstraints(); sendRequest (null, new JDAPUnbindRequest (), null, cons); } + // must be set after the call to sendRequest + m_doRun =false; + if ( m_thread != null && m_thread != Thread.currentThread()) { m_thread.interrupt(); @@ -262,11 +288,12 @@ class LDAPConnThread extends Thread { } } - cleanUp(); - } catch (Exception e) { LDAPConnection.printDebug(e.toString()); } + finally { + cleanUp(); + } } } @@ -334,6 +361,7 @@ class LDAPConnThread extends Thread { c.deregisterConnection(); } } + m_registered.clear(); m_registered = null; m_messages = null; m_requests.clear(); @@ -345,45 +373,58 @@ class LDAPConnThread extends Thread { * Sleep if there is a backlog of search results */ private void checkBacklog() throws InterruptedException{ - boolean doWait; - do { - doWait = false; + + while (true) { + + if (m_requests.size() == 0) { + return; + } + Enumeration listeners = m_requests.elements(); while( listeners.hasMoreElements() ) { - LDAPMessageQueue l = - (LDAPMessageQueue)listeners.nextElement(); + LDAPMessageQueue l = (LDAPMessageQueue)listeners.nextElement(); + // If there are any threads waiting for a regular response // message, we have to go read the next incoming message if ( !(l instanceof LDAPSearchListener) ) { - doWait = false; - break; + return; } - // If the backlog of any search thread is too great, - // wait for it to diminish, but if this is a synchronous - // search, then just keep reading + LDAPSearchListener sl = (LDAPSearchListener)l; - // Asynch operation ? - if (sl.isAsynchOp()) { - if (sl.getMessageCount() >= sl.getSearchConstraints().getMaxBacklog()) { - doWait = true; - } + // should never happen, but just in case + if (sl.getSearchConstraints() == null) { + return; } - // synch op with non-zero batch size ? - else if (sl.getSearchConstraints().getBatchSize() != 0) { - if (sl.getMessageCount() >= sl.getSearchConstraints().getMaxBacklog()) { - doWait = true; - } + + int slMaxBacklog = sl.getSearchConstraints().getMaxBacklog(); + int slBatchSize = sl.getSearchConstraints().getBatchSize(); + + // Disabled backlog check ? + if (slMaxBacklog == 0) { + return; + } + + // Synch op with zero batch size ? + if (!sl.isAsynchOp() && slBatchSize == 0) { + return; + } + + // Max backlog not reached for at least one listener ? + // (if multiple requests are in progress) + if (sl.getMessageCount() < slMaxBacklog) { + return; } } - if ( doWait ) { - synchronized(this) { - wait(); - } + + synchronized(this) { + wait(3000); } - } while ( doWait ); + } } + + /** * This is called when a search result has been retrieved from the incoming * queue. We use the notification to unblock the listener thread, if it @@ -414,8 +455,11 @@ class LDAPConnThread extends Thread { nread[0] = 0; try { - // Avoid too great a backlog of results - checkBacklog(); + // Check after every BACKLOG_CHKCNT messages if the backlog is not too high + if (--m_backlogCheckCounter <= 0) { + m_backlogCheckCounter = BACKLOG_CHKCNT; + checkBacklog(); + } BERElement element = BERElement.getElement(decoder, m_serverInput, @@ -423,7 +467,7 @@ class LDAPConnThread extends Thread { msg = LDAPMessage.parseMessage(element); if (m_traceOutput != null) { - logLDAPMessage(msg); + logTraceMessage(msg.toTraceString()); } // passed in the ber element size to approximate the size of the cache @@ -434,9 +478,9 @@ class LDAPConnThread extends Thread { } catch (Exception e) { if (m_doRun) { networkError(e); - m_doRun =false; } else { + // interrupted from deregister() synchronized (this) { m_thread = null; notifyAll(); @@ -455,7 +499,6 @@ class LDAPConnThread extends Thread { private void processResponse (LDAPMessage msg, int size) { Integer messageID = new Integer (msg.getMessageID()); LDAPMessageQueue l = (LDAPMessageQueue)m_requests.get (messageID); - if (l == null) { return; /* nobody is waiting for this response (!) */ } @@ -486,6 +529,9 @@ class LDAPConnThread extends Thread { if (msg instanceof LDAPResponse) { m_requests.remove (messageID); + if (m_requests.size() == 0) { + m_backlogCheckCounter = BACKLOG_CHKCNT; + } } } @@ -588,17 +634,38 @@ class LDAPConnThread extends Thread { * @param id Message ID for which to discard responses. */ void abandon (int id ) { + + if (!m_doRun) { + return; + } + LDAPMessageQueue l = (LDAPMessageQueue)m_requests.remove(new Integer(id)); // Clean up cache if enabled if (m_messages != null) { m_messages.remove(new Integer(id)); - } + } if (l != null) { l.removeRequest(id); } resultRetrieved(); // If LDAPConnThread is blocked in checkBacklog() } + /** + * Change listener for a message ID. Required when LDAPMessageQueue.merge() + * is invoked. + * @param id Message ID for which to chanage the listener. + * @return Previous listener. + */ + LDAPMessageQueue changeListener (int id, LDAPMessageQueue toNotify) { + + if (!m_doRun) { + toNotify.setException(this, new LDAPException("Server down", + LDAPException.OTHER)); + return null; + } + return (LDAPMessageQueue) m_requests.put (new Integer (id), toNotify); + } + /** * Handles network errors. Basically shuts down the whole connection. * @param e The exception which was caught while trying to read from @@ -606,6 +673,8 @@ class LDAPConnThread extends Thread { */ private synchronized void networkError (Exception e) { + m_doRun =false; + // notify the Connection Setup Manager that the connection is lost m_connMgr.invalidateConnection(); diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnection.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnection.java index 1b6be8b43602..0c53cf5a01c9 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnection.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPConnection.java @@ -260,11 +260,11 @@ public class LDAPConnection /** * Properties */ - private final static Float SdkVersion = new Float(4.13f); + private final static Float SdkVersion = new Float(4.14f); private final static Float ProtocolVersion = new Float(3.0f); private final static String SecurityVersion = new String("none,simple,sasl"); private final static Float MajorVersion = new Float(4.0f); - private final static Float MinorVersion = new Float(0.13f); + private final static Float MinorVersion = new Float(0.14f); private final static String DELIM = "#"; private final static String PersistSearchPackageName = "netscape.ldap.controls.LDAPPersistSearchControl"; @@ -1746,10 +1746,10 @@ public class LDAPConnection LDAPResponseListener myListener = getResponseListener (); try { - if (m_referralConnection != null) { + if (m_referralConnection != null && m_referralConnection.isConnected()) { m_referralConnection.disconnect(); - m_referralConnection = null; } + m_referralConnection = null; m_bound = false; sendRequest(new JDAPBindRequest(m_protocolVersion, m_boundDN, m_boundPasswd), @@ -1883,25 +1883,26 @@ public class LDAPConnection * @see netscape.ldap.LDAPConnection#connect(java.lang.String, int, java.lang.String, java.lang.String) */ public synchronized void disconnect() throws LDAPException { - if (m_referralConnection != null) { - m_referralConnection.disconnect(); - m_referralConnection = null; - } - if (!isConnected()) throw new LDAPException ( "unable to disconnect() without connecting", LDAPException.OTHER ); // Clone the Connection Setup Manager if the connection is shared - if (m_thread.getClientCount() > 1) { + if (m_thread.isRunning() && m_thread.getClientCount() > 1) { m_connMgr = (LDAPConnSetupMgr) m_connMgr.clone(); m_connMgr.disconnect(); } - + + if (m_referralConnection != null && m_referralConnection.isConnected()) { + m_referralConnection.disconnect(); + } + m_referralConnection = null; + if (m_cache != null) { m_cache.removeReference(); m_cache = null; } + deleteThreadConnEntry(); deregisterConnection(); } @@ -1934,7 +1935,9 @@ public class LDAPConnection * Remove the association between this object and the connection thread */ synchronized void deregisterConnection() { - m_thread.deregister(this); + if (m_thread != null && m_thread.isRunning()) { + m_thread.deregister(this); + } m_thread = null; m_bound = false; } @@ -4165,7 +4168,7 @@ public class LDAPConnection * Modifying this option sets the LDAPv2.BIND option to null. *

By default, the value of this option is null. * - * LDAPv2.BIND>/CODE> + * LDAPv2.BIND * LDAPBind * Specifies an object with a class that implements the * LDAPBind @@ -4207,7 +4210,8 @@ public class LDAPConnection * Integer * Specifies the maximum number of search results to accumulate in an * LDAPSearchResults before suspending the reading of input from the server. - *

By default, the value of this option is 100. + *

By default, the value of this option is 100. The value 0 means there + * is no limit. *

* @return the value for the option wrapped in an object. (You * need to cast the returned value as its appropriate type. For @@ -4363,7 +4367,7 @@ public class LDAPConnection * Modifying this option sets the LDAPv2.BIND option to null. *

By default, the value of this option is null. * - * LDAPv2.BIND>/CODE> + * LDAPv2.BIND * LDAPBind * Specifies an object with a class that implements the * LDAPBind @@ -4405,7 +4409,8 @@ public class LDAPConnection * Integer * Specifies the maximum number of search results to accumulate in an * LDAPSearchResults before suspending the reading of input from the server. - *

By default, the value of this option is 100. + *

By default, the value of this option is 100. The value 0 means there + * is no limit. *

* @param value the value to assign to the option. The value must be * the java.lang object wrapper for the appropriate parameter @@ -4481,14 +4486,8 @@ public class LDAPConnection LDAPException.PARAM_ERROR ); return; case MAXBACKLOG: - int val = ((Integer)value).intValue(); - if ( val < 1 ) { - throw new LDAPException ( "MAXBACKLOG must be at least 1", - LDAPException.PARAM_ERROR ); - } else { - cons.setMaxBacklog(((Integer)value).intValue()); - } - return; + cons.setMaxBacklog(((Integer)value).intValue()); + return; default: throw new LDAPException ("invalid option", LDAPException.PARAM_ERROR ); @@ -4808,6 +4807,7 @@ public class LDAPConnection else { l = (LDAPSearchListener)m_searchListeners.elementAt (0); m_searchListeners.removeElementAt (0); + l.setSearchConstraints(cons); } return l; } @@ -5010,7 +5010,7 @@ public class LDAPConnection } - private String createReferralConnectList(LDAPUrl[] urls, boolean allowEmptyHost) { + private String createReferralConnectList(LDAPUrl[] urls) { String connectList = ""; String host = null; int port =0; @@ -5019,11 +5019,9 @@ public class LDAPConnection host = urls[i].getHost(); port = urls[i].getPort(); if ( (host == null) || (host.length() < 1) ) { - if (allowEmptyHost) { - // If no host:port was specified, use the latest (hop-wise) parameters - host = getHost(); - port = getPort(); - } + // If no host:port was specified, use the latest (hop-wise) parameters + host = getHost(); + port = getPort(); } connectList += (i==0 ? "" : " ") + host+":"+port; } @@ -5035,7 +5033,13 @@ public class LDAPConnection String connHost = ldc.getHost(); int connPort = ldc.getPort(); for (int i = 0; i < urls.length; i++) { - if (connHost.equals(urls[i].getHost()) && connPort == urls[i].getPort()) { + if (urls[i].getHost() == null || urls[i].getHost().length() < 1) { + // No host:port specified, compare with the latest (hop-wise) parameters + if (connHost.equals(getHost()) && connPort == getPort()) { + return urls[i]; + } + } + else if (connHost.equals(urls[i].getHost()) && connPort == urls[i].getPort()) { return urls[i]; } } @@ -5061,7 +5065,7 @@ public class LDAPConnection } String connectList = - createReferralConnectList(e.getURLs(), /*allowEmptyHost=*/false); + createReferralConnectList(e.getURLs()); // If there are no referrals (because the server isn't set up for // them), give up here if (connectList == null) { @@ -5071,7 +5075,17 @@ public class LDAPConnection LDAPConnection connection = null; connection = prepareReferral(connectList, cons); - connection.authenticate(m_protocolVersion, m_boundDN, m_boundPasswd); + try { + connection.authenticate(m_protocolVersion, m_boundDN, m_boundPasswd); + } + catch (LDAPException authEx) { + // Disconnect needed to terminate the LDAPConnThread + try { + connection.disconnect(); + } + catch (LDAPException ignore) {} + throw authEx; + } return connection; } @@ -5117,14 +5131,14 @@ public class LDAPConnection LDAPUrl referralURL = null; LDAPConnection connection = null; - if (m_referralConnection != null) { + if (m_referralConnection != null && m_referralConnection.isConnected()) { referralURL = findReferralURL(m_referralConnection, urls); } if (referralURL != null) { connection = m_referralConnection; } else { - String connectList = createReferralConnectList(urls, /*allowEmptyHost=*/true); + String connectList = createReferralConnectList(urls); connection = prepareReferral( connectList, cons ); // which one did we connect to... @@ -5240,7 +5254,7 @@ public class LDAPConnection return null; } - String connectList = createReferralConnectList(u, /*allowEmptyHost=*/false); + String connectList = createReferralConnectList(u); LDAPConnection connection = prepareReferral( connectList, cons); referralRebind(connection, cons); LDAPExtendedOperation results = @@ -5303,17 +5317,6 @@ public class LDAPConnection return null; } - /** - * This is called when a search result has been retrieved from the incoming - * queue. We use the notification to unblock the listener thread, if it - * is waiting for the backlog to lighten. - */ - void resultRetrieved() { - if ( m_thread != null ) { - m_thread.resultRetrieved(); - } - } - /** * Sets up basic connection privileges for Communicator. * @return true if in Communicator and connections okay. diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessage.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessage.java index 8a4de96438f4..8adfd7cb30d9 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessage.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessage.java @@ -26,7 +26,6 @@ import netscape.ldap.client.opers.*; import netscape.ldap.ber.stream.*; import java.io.*; import java.net.*; -import java.text.SimpleDateFormat; /** @@ -81,9 +80,6 @@ public class LDAPMessage implements java.io.Serializable { private JDAPProtocolOp m_protocolOp = null; private LDAPControl m_controls[] = null; - // Time Stemp format Hour(0-23):Minute:Second.Milliseconds used for trace msgs - static SimpleDateFormat m_timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); - /** * Constructs a ldap message. * @param msgid message identifier @@ -269,10 +265,8 @@ public class LDAPMessage implements java.io.Serializable { * the time stamp. Used for message trace * @return ldap message with the time stamp */ - String toTraceString() { - String timeStamp = m_timeFormat.format(new Date()); - StringBuffer sb = new StringBuffer(timeStamp); - sb.append(" "); + StringBuffer toTraceString() { + StringBuffer sb = new StringBuffer(" op="); sb.append(m_msgid); sb.append(" "); sb.append(m_protocolOp.toString()); @@ -281,6 +275,6 @@ public class LDAPMessage implements java.io.Serializable { sb.append(" "); sb.append(m_controls[i].toString()); } - return sb.toString(); + return sb; } } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessageQueue.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessageQueue.java index eb93c8599b3d..ae49fa86db42 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessageQueue.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPMessageQueue.java @@ -235,22 +235,34 @@ class LDAPMessageQueue implements java.io.Serializable { * new request with the existing one. * @param mq2 message queue to merge with this one */ - synchronized void merge(LDAPMessageQueue mq2) { - synchronized (mq2) { - for (int i=0; i < mq2.m_requestList.size(); i++) { - m_requestList.addElement(mq2.m_requestList.elementAt(i)); - } - for (int i=0; i < mq2.m_messageQueue.size(); i++) { - m_messageQueue.addElement(mq2.m_messageQueue.elementAt(i)); - } - if (mq2.m_exception != null) { - m_exception = mq2.m_exception; - } + void merge(LDAPMessageQueue mq2) { + + // Yield just in case the LDAPConnThread is in the process of + // dispatching a message + Thread.yield(); + + synchronized(this) { - mq2.reset(); - notifyAll(); // notify for mq2 + synchronized (mq2) { + for (int i=0; i < mq2.m_messageQueue.size(); i++) { + m_messageQueue.addElement(mq2.m_messageQueue.elementAt(i)); + } + if (mq2.m_exception != null) { + m_exception = mq2.m_exception; + } + for (int i=0; i < mq2.m_requestList.size(); i++) { + RequestEntry entry = (RequestEntry)mq2.m_requestList.elementAt(i); + m_requestList.addElement(entry); + // Notify LDAPConnThread to redirect mq2 designated responses to this mq + entry.connThread.changeListener(entry.id, this); + } + + mq2.reset(); + notifyAll(); // notify for mq2 + } + + notifyAll(); // notify this mq } - notifyAll(); // notify this mq } @@ -278,7 +290,7 @@ class LDAPMessageQueue implements java.io.Serializable { getConnection(msg.getMessageID()).markConnAsBound(); } } - + notifyAll (); } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSchema.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSchema.java index 87040be13c37..f1d0362a8acc 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSchema.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSchema.java @@ -869,7 +869,8 @@ public class LDAPSchema implements java.io.Serializable { private static LDAPEntry readSchema( LDAPConnection ld, String dn ) throws LDAPException { - return readSchema( ld, dn, new String[] { "*", "ldapsyntaxes" } ); + return readSchema( ld, dn, new String[] { "*", "ldapSyntaxes", + "matchingRules", "attributeTypes", "objectClasses" } ); } /** diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchConstraints.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchConstraints.java index aae42c85d4b1..34d0822d4824 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchConstraints.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchConstraints.java @@ -38,7 +38,7 @@ public class LDAPSearchConstraints extends LDAPConstraints private int maxRes; private int batch; private int serverTimeLimit; - private int m_maxBacklog = 100; + private int maxBacklog = 100; /** * Constructs an LDAPSearchConstraints object that specifies @@ -280,20 +280,20 @@ public class LDAPSearchConstraints extends LDAPConstraints * Set the maximum number of unread entries any search listener can * have before we stop reading from the server. * @param backlog the maximum number of unread entries per listener - * @deprecated Use LDAPConnection.getOption() + * @deprecated Use LDAPConnection.setOption() */ public void setMaxBacklog( int backlog ) { - m_maxBacklog = backlog; + maxBacklog = backlog; } /** * Get the maximum number of unread entries any search listener can * have before we stop reading from the server. * @return the maximum number of unread entries per listener. - * @deprecated Use LDAPConnection.setOption() + * @deprecated Use LDAPConnection.getOption() */ public int getMaxBacklog() { - return m_maxBacklog; + return maxBacklog; } /** @@ -307,6 +307,7 @@ public class LDAPSearchConstraints extends LDAPConstraints o.deref = this.deref; o.maxRes = this.maxRes; o.batch = this.batch; + o.maxBacklog = this.maxBacklog; o.setHopLimit(this.getHopLimit()); o.setReferrals(this.getReferrals()); @@ -354,7 +355,8 @@ public class LDAPSearchConstraints extends LDAPConstraints sb.append("size limit " + maxRes + ", "); sb.append("server time limit " + serverTimeLimit + ", "); sb.append("aliases " + deref + ", "); - sb.append("batch size " + batch); + sb.append("batch size " + batch + ", "); + sb.append("max backlog " + maxBacklog); sb.append('}'); return sb.toString(); diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchListener.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchListener.java index f8e9b2b3c465..aa6cad50010c 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchListener.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPSearchListener.java @@ -85,11 +85,11 @@ public class LDAPSearchListener extends LDAPMessageQueue { // Notify LDAPConnThread to wake up if backlog limit has been reached if (result instanceof LDAPSearchResult || result instanceof LDAPSearchResultReference) { - LDAPConnection ld = getConnection(result.getMessageID()); - if (ld != null) { - ld.resultRetrieved(); - } - } + LDAPConnThread connThread = getConnThread(result.getMessageID()); + if (connThread != null) { + connThread.resultRetrieved(); + } + } return result; } @@ -143,6 +143,23 @@ public class LDAPSearchListener extends LDAPMessageQueue { return m_constraints; } + /** + * Set new search constraints object. + * @param cons LDAP search constraints + */ + void setSearchConstraints(LDAPSearchConstraints cons) { + m_constraints = cons; + } + + /** + * Resets the state of this object, so it can be recycled. + * Used by LDAPConnection synchronous operations. + */ + void reset () { + super.reset(); + m_constraints = null; + } + /** * Set the key of the cache entry. The listener needs to know this value * when the results get processed in the queue. After the results have been diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPUrl.java b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPUrl.java index cc14792f1327..d0620e4046f5 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/LDAPUrl.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/LDAPUrl.java @@ -549,7 +549,8 @@ public class LDAPUrl implements java.io.Serializable { // the default one. try { // First try iPlanet JSSSocketFactory - m_factory = new JSSSocketFactory(); + Class c = Class.forName("netscape.ldap.factory.JSSSocketFactory"); + m_factory = (LDAPSocketFactory) c.newInstance(); } catch (Throwable e) { } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/client/JDAPFilter.java b/directory/java-sdk/ldapjdk/netscape/ldap/client/JDAPFilter.java index 7e4fc3d1b27e..8e9ef9879439 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/client/JDAPFilter.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/client/JDAPFilter.java @@ -80,12 +80,8 @@ public abstract class JDAPFilter { public static JDAPFilter getFilter(String filter) { String f = new String(filter); f.trim(); - if (f.startsWith("(") || f.endsWith(")")) { - if (f.startsWith("(") && f.endsWith(")")) { - return getFilterComp(f.substring(1,f.length()-1)); - } - //unbalanced parentheses - throw new IllegalArgumentException("Bad search filter"); + if (f.startsWith("(") && f.endsWith(")")) { + return getFilterComp(f.substring(1,f.length()-1)); } return getFilterComp(filter); } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPAbandonRequest.java b/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPAbandonRequest.java index 205110b6277e..13fe7a343845 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPAbandonRequest.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPAbandonRequest.java @@ -71,15 +71,9 @@ public class JDAPAbandonRequest implements JDAPProtocolOp { * 0x50 (implicit tagged integer) * 0x01 (length) * 0x01 (message id) - * [*] umich-ldap-v3.0: - * 0x50 (tag APPLICATION|CONSTRUCTED) - * 0x85 0x00 0x00 0x00 0x07 (tag length) - * 0x02 (integer tag) - * 0x85 0x00 0x00 0x00 0x01 0x01 (message id) */ BERInteger i = new BERInteger(m_msgid); - BERTag element = new BERTag(BERTag.APPLICATION|BERTag.CONSTRUCTED|16, - i, true); + BERTag element = new BERTag(BERTag.APPLICATION|16, i, true); return element; } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPBindRequest.java b/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPBindRequest.java index 33d8c2affee5..bf6bcb7b9513 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPBindRequest.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/client/opers/JDAPBindRequest.java @@ -163,7 +163,7 @@ public class JDAPBindRequest implements JDAPProtocolOp { */ public String getParamString() { return "{version=" + m_version + ", name=" + m_name + - ", authentication=" + m_password + "}"; + ", authentication=" + ((m_password == null) ? m_password : "********") + "}"; } /** diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/factory/JSSESocketFactory.java b/directory/java-sdk/ldapjdk/netscape/ldap/factory/JSSESocketFactory.java index 5961b22b5c11..25a6306976a7 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/factory/JSSESocketFactory.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/factory/JSSESocketFactory.java @@ -26,7 +26,6 @@ import java.net.*; import java.io.*; import javax.net.ssl.*; import netscape.ldap.*; -import com.sun.net.ssl.*; /** * Creates an SSL socket connection to a server, using the JSSE package @@ -74,10 +73,16 @@ public class JSSESocketFactory SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); sock = (SSLSocket)factory.createSocket(host, port); + if (suites != null) { sock.setEnabledCipherSuites(suites); - sock.startHandshake(); } + + // Start handshake manually to immediately expose potential + // SSL errors as exceptions. Otherwise, handshake will take + // place first time the data are written to the socket. + sock.startHandshake(); + } catch (UnknownHostException e) { throw new LDAPException("SSL connection to " + host + ":" + port + ", " + e.getMessage(), @@ -87,7 +92,7 @@ public class JSSESocketFactory ":" + port + ", " + f.getMessage(), LDAPException.CONNECT_ERROR); } - + return sock; } } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/util/DN.java b/directory/java-sdk/ldapjdk/netscape/ldap/util/DN.java index 0917b0c70803..13c6f9bb1c95 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/util/DN.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/util/DN.java @@ -93,56 +93,17 @@ public final class DN implements Serializable { * @param dn string representation of the distinguished name */ public DN(String dn) { - if (dn == null) - return; - int index; + String neutralDN = neutralizeEscapes(dn); + if (neutralDN == null) { + return; // malformed + } + // RFC1485 - if (isRFC(dn)) { - StringBuffer buffer = new StringBuffer(dn); - - int i=0; - StringBuffer rbuffer = new StringBuffer(); - boolean openQuotes = false; - while (i < buffer.length()) { - rbuffer.append(buffer.charAt(i)); - if (buffer.charAt(i) == '\\') { - char c = buffer.charAt(i+1); - for (int j=0; j= 0; i--) { m_rdns.addElement(rdns.elementAt(i)); - } - } else if (RDN.isRDN(dn)) { + } + } + else if (RDN.isRDN(dn)) { m_rdns.addElement(new RDN(dn)); } } + /** + * Neutralize backslash escapes and quoted sequences for easy parsing. + * @return dn string with disabled escapes or null if malformed dn + */ + private String neutralizeEscapes(String dn) { + String neutralDN = RDN.neutralizeEscapes(dn); + if (neutralDN == null) { + return null; // malformed + } + + String dn2 = neutralDN.trim(); + if (dn2.length() == 0) { + return neutralDN; + } + if (dn2.charAt(0) == ';' || dn2.charAt(0) == ',') { + return null; // malformed + } + int lastIdx = dn2.length() -1; + if (dn2.charAt(lastIdx) == ';' || dn2.charAt(lastIdx) == ',') { + return null; // malformed + } + return neutralDN; + } + + /** + * Parse RDNs in the DN + */ + private void parseRDNs(String neutralDN, String dn, String sep) { + int startIdx=0, endIdx=0; + RDN rdn = null; + StringTokenizer tok = new StringTokenizer(neutralDN, sep); + while (tok.hasMoreElements()) { + String neutralRDN = tok.nextToken(); + endIdx = startIdx + neutralRDN.length(); + rdn = new RDN (dn.substring(startIdx, endIdx)); + if (rdn.getTypes() != null) { + m_rdns.addElement(rdn); + } + else { // malformed rdn + m_rdns.removeAllElements(); + return; + } + startIdx = endIdx + 1; + } + } + /** * Adds the specified relative distinguished name (RDN) to the * beginning of the current DN. @@ -448,32 +456,8 @@ public final class DN implements Serializable { return true; } - private boolean isRFC(String dn) { - int index =dn.indexOf(','); - /* Can't have the first or last character be the first unescaped comma */ - while ((index > 0) && (index < (dn.length() -1))) { - /* Found an unescaped comma */ - if (dn.charAt(index-1) != '\\') { - return true; - } - /* Found an escaped comma, keep searching */ - index=dn.indexOf(',',index+1); - } - return false; - } - - private boolean appendRDN(StringBuffer buffer) { - String rdn = new String(buffer); - if (RDN.isRDN(rdn)) { - m_rdns.addElement(new RDN(rdn)); - return true; - } - m_rdns.removeAllElements(); - return false; - } - /** * Array of the characters that may be escaped in a DN. */ - public static final char[] ESCAPED_CHAR = {',', '+', '"', '\\', ';'}; + public static final char[] ESCAPED_CHAR = {',', '+', '"', '\\', '<', '>', ';'}; } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIF.java b/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIF.java index 42a9feb17a75..86dcebdb0b5c 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIF.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIF.java @@ -136,7 +136,7 @@ public class LDIF implements Serializable { m_version = Integer.parseInt( line.substring("version:".length()).trim() ); if ( m_version != 1 ) { - throw( new IOException( "Unexpected " + line ) ); + throwLDIFException( "Unexpected " + line ); } // Do the next record line = d.readLine(); @@ -150,7 +150,7 @@ public class LDIF implements Serializable { } if (!line.startsWith("dn:")) - throw new IOException("no dn found in <" + line + ">"); + throwLDIFException("expecting dn:"); dn = line.substring(3).trim(); if (dn.startsWith(":") && (dn.length() > 1)) { String substr = dn.substring(1).trim(); @@ -194,7 +194,7 @@ public class LDIF implements Serializable { changetype.equals("modrdn")) { lc = parse_moddn_spec(d); } else { - throw new IOException("change type not supported"); + throwLDIFException("change type not supported"); } return lc; } @@ -222,8 +222,7 @@ public class LDIF implements Serializable { int idx = line.indexOf(':'); /* Must have a colon */ if (idx == -1) - throw new IOException("no ':' found in <" + - line + ">"); + throwLDIFException("no ':' found"); /* attribute type */ newtype = line.substring(0,idx).toLowerCase(); val = ""; @@ -241,7 +240,7 @@ public class LDIF implements Serializable { String filename = url.getFile(); val = getFileContent(filename); } catch (MalformedURLException ex) { - throw new IOException( + throwLDIFException( ex + ": cannot construct url "+ line.substring(idx+1).trim()); @@ -350,7 +349,7 @@ public class LDIF implements Serializable { } controlVector.addElement( parse_control_spec( line ) ); } else { - throw new IOException("invalid SEP" ); + throwLDIFException("invalid SEP" ); } line = d.readLine(); } @@ -384,7 +383,7 @@ public class LDIF implements Serializable { } else if (line.startsWith("replace:")) { oper = LDAPModification.REPLACE; } else - throw new IOException("unknown modify type"); + throwLDIFException("unknown modify type"); LDIFAttributeContent ac = (LDIFAttributeContent)parse_ldif_content(d); @@ -407,12 +406,12 @@ public class LDIF implements Serializable { } else { int index = line.indexOf(":"); if (index == -1) - throw new IOException("colon missing in "+line); + throwLDIFException("colon missing in "+line); String attrName = line.substring(index+1).trim(); if (oper == LDAPModification.ADD) - throw new IOException("add operation needs the value for attribute "+attrName); + throwLDIFException("add operation needs the value for attribute "+attrName); LDAPAttribute attr = new LDAPAttribute(attrName); LDAPModification mod = new LDAPModification(oper, attr); mc.addElement(mod); @@ -456,7 +455,7 @@ public class LDIF implements Serializable { else if (str.equals("1")) mc.setDeleteOldRDN(true); else - throw new IOException("Incorrect input for deleteOldRdn "); + throwLDIFException("Incorrect input for deleteOldRdn "); } else if (line.startsWith("newsuperior:") && (line.length() > ("newsuperior:".length()+1))) { mc.setNewParent(line.substring( @@ -518,7 +517,7 @@ public class LDIF implements Serializable { int idx = line.indexOf(':') + 2; /* OID, must be present */ if ( idx >= len ) { - throw new IOException("OID required for control"); + throwLDIFException("OID required for control"); } line = line.substring(idx).trim(); idx = line.indexOf(' '); @@ -540,7 +539,7 @@ public class LDIF implements Serializable { } else if ( criticalVal.compareTo("false") == 0 ) { criticality = false; } else { - throw new IOException( + throwLDIFException( "Criticality for control must be true" + " or false, not " + criticalVal); } @@ -560,7 +559,7 @@ public class LDIF implements Serializable { String filename = url.getFile(); val = getFileContent(filename); } catch (MalformedURLException ex) { - throw new IOException( + throwLDIFException( ex + ": cannot construct url "+ urlString); } @@ -640,6 +639,15 @@ public class LDIF implements Serializable { return "LDIF {" + m_source + "}"; } + /** + * Throws a LDIF file exception including the current line number. + * @param msg Error message + */ + protected void throwLDIFException(String msg)throws IOException { + throw new IOException ("line " + + (m_currLineNum-m_continuationLength) + ": " + msg); + } + /** * Internal variables */ @@ -649,6 +657,8 @@ public class LDIF implements Serializable { private String m_source = null; private MimeBase64Decoder m_decoder = null; private boolean m_currEntryDone = false; + private int m_currLineNum; + private int m_continuationLength; /* Concatenate continuation lines, if present */ class LineReader { @@ -662,6 +672,7 @@ public class LDIF implements Serializable { String readLine() throws IOException { String line = null; String result = null; + int readCnt = 0, continuationLength = 0; do { /* Leftover line from last time? */ if ( _next != null ) { @@ -671,6 +682,7 @@ public class LDIF implements Serializable { line = _d.readLine(); } if (line != null) { + readCnt++; /* Empty line means end of record */ if( line.length() < 1 ) { if ( result == null ) @@ -691,19 +703,28 @@ public class LDIF implements Serializable { } } else { /* Continuation line */ - if ( result == null ) - throw new IOException("continuation out of " + - "nowhere <" + - line + ">"); + if ( result == null ) { + m_currLineNum += readCnt; + throwLDIFException("continuation out of nowhere"); + } result += line.substring(1); + continuationLength++; } } else { /* End of file */ break; } } while ( true ); - if ( line == null ) - m_done = true; + + m_done = ( line == null ); + + m_currLineNum += readCnt; + if (_next != null) { + // read one line ahead + m_currLineNum--; + } + m_continuationLength = continuationLength; + return result; } private BufferedReader _d; diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIFWriter.java b/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIFWriter.java index 5e17523346c7..08c1a8d3b7e5 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIFWriter.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/util/LDIFWriter.java @@ -17,7 +17,8 @@ * Copyright (C) 1999 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Contributor(s): + * bugzilla 62700: Joe Rank (joer@trapdoor.net) */ package netscape.ldap.util; @@ -92,7 +93,12 @@ public class LDIFWriter extends LDAPWriter { /* Loop on values for this attribute */ Enumeration enumVals = attr.getByteValues(); - if ( enumVals != null ) { + if ( enumVals == null ) { + printString( attrName + m_sep + ' ' ); + return; + } + + while (enumVals.hasMoreElements()) { if ( m_toFiles ) { try { FileOutputStream f = getTempFile( attrName ); @@ -122,8 +128,6 @@ public class LDIFWriter extends LDAPWriter { } } } - } else { - printString( attrName + m_sep + ' ' ); } } diff --git a/directory/java-sdk/ldapjdk/netscape/ldap/util/RDN.java b/directory/java-sdk/ldapjdk/netscape/ldap/util/RDN.java index 59e913aa4e70..0f9aafdda7d5 100644 --- a/directory/java-sdk/ldapjdk/netscape/ldap/util/RDN.java +++ b/directory/java-sdk/ldapjdk/netscape/ldap/util/RDN.java @@ -65,7 +65,11 @@ public final class RDN implements java.io.Serializable { * @param rdn DN component */ public RDN( String rdn ) { - int index = rdn.indexOf( "=" ); + String neutralRDN = neutralizeEscapes(rdn); + if (neutralRDN == null) { + return; // malformed RDN + } + int index = neutralRDN.indexOf( "=" ); int next_plus; // if the rdn doesnt have = or = positions right at the beginning of the rdn @@ -76,17 +80,17 @@ public final class RDN implements java.io.Serializable { Vector types = new Vector(); types.addElement( rdn.substring( 0, index ).trim() ); - next_plus = findNextMVSeparator( rdn, index ); + next_plus = neutralRDN.indexOf( '+', index ); while ( next_plus != -1 ) { m_ismultivalued = true; - values.addElement( rdn.substring( index + 1, next_plus - 1 ).trim() ); - index = rdn.indexOf( "=", next_plus + 1 ); + values.addElement( rdn.substring( index + 1, next_plus).trim() ); + index = neutralRDN.indexOf( "=", next_plus + 1 ); if ( index == -1 ) { // malformed RDN? return; } types.addElement( rdn.substring( next_plus + 1, index ).trim() ); - next_plus = findNextMVSeparator( rdn, index ); + next_plus = neutralRDN.indexOf('+', index ); } values.addElement( rdn.substring( index + 1 ).trim() ); @@ -95,47 +99,102 @@ public final class RDN implements java.io.Serializable { for( int i = 0; i < types.size(); i++ ) { m_type[i] = (String)types.elementAt( i ); + if (!isValidType(m_type[i])) { + m_type = m_value = null; + return; // malformed + } m_value[i] = (String)values.elementAt( i ); + if (!isValidValue(m_value[i])) { + m_type = m_value = null; + return; // malformed + } } } - /* find the next '+' that isn't escaped or in quotes */ - int findNextMVSeparator( String str, int offset ) { - int next_plus = str.indexOf( '+', offset ); - int next_open_q = str.indexOf( '"', offset ); - int next_close_q = -1; - - if ( next_plus == offset ) { - return offset; - } - - if ( next_open_q > -1 ) { - next_close_q = str.indexOf( '"', next_open_q + 1 ); - } - - while ( next_plus != -1 ) { - if ( str.charAt( next_plus - 1 ) != '\\' && - !( next_open_q < next_plus && next_plus < next_close_q ) ) { - return next_plus; - } - - next_plus = str.indexOf( '+', next_plus + 1 ); - if ( next_open_q > -1 && next_close_q > -1 ) { - if ( next_close_q < next_plus ) { - next_open_q = str.indexOf( '"', next_close_q + 1 ); + /** + * Neutralize backslash escapes and quoted sequences for easy parsing. + * @return rdn string with disabled escapes or null if malformed rdn + */ + static String neutralizeEscapes(String rdn) { + if (rdn == null) { + return null; + } + StringBuffer sb = new StringBuffer(rdn); + boolean quoteOn = false; + // first pass, disable backslash escapes + for (int i=0; i < sb.length(); i++) { + if (sb.charAt(i) =='\\') { + sb.setCharAt(i, 'x'); + if (i < sb.length()-1) { + sb.setCharAt(i+1, 'x'); + } + else { + return null; } - } else { - next_open_q = -1; } - - next_close_q = next_open_q > -1 ? str.indexOf( '"', next_open_q + 1 ) - : -1; } - - return -1; - + // second pass, disable quoted sequences + for (int i=0; i < sb.length(); i++) { + if (sb.charAt(i) == '"') { + quoteOn = !quoteOn; + continue; + } + if (quoteOn) { + sb.setCharAt(i, 'x'); + } + } + return quoteOn ? null : sb.toString(); } - + + /** + * Type names can not contain any DN special characters + */ + private boolean isValidType(String type) { + if (type == null || type.length() < 1) { + return false; + } + for (int i=0; i< type.length(); i++) { + for (int j=0; j < DN.ESCAPED_CHAR.length; j++) { + if (type.charAt(i) == DN.ESCAPED_CHAR[j]) { + return false; + } + } + } + return true; + } + + /** + * Values can contain only single quote sequence, where quotes are + * at the beginning and the end of the sequence + */ + private boolean isValidValue(String val) { + if (val == null || val.length() < 1) { + return false; + } + // count unescaped '"' + int cnt=0, i=0; + while (i >=0 && i < val.length()) { + i = val.indexOf('"', i); + if (i >= 0) { + if (i==0 || (val.charAt(i-1) != '\\')) { + cnt++; + } + i++; + } + } + if (cnt == 0) { + return true; + } + else if (cnt != 2) { // can have only two of them surrounding the value + return false; + } + else if (val.charAt(0) != '"' || val.charAt(val.length()-1) != '"') { + return false; + } + + return true; + } + /** * Returns the DN component as the first element in an * array of strings. @@ -162,7 +221,10 @@ public final class RDN implements java.io.Serializable { * @deprecated use getTypes() instead. */ public String getType() { - return m_type[0]; + if (m_type != null && m_type.length > 0) { + return m_type[0]; + } + return null; } /** @@ -179,7 +241,10 @@ public final class RDN implements java.io.Serializable { * @deprecated use getValues() instead. */ public String getValue() { - return m_value[0]; + if (m_value != null && m_value.length > 0) { + return m_value[0]; + } + return null; } /** @@ -203,10 +268,13 @@ public final class RDN implements java.io.Serializable { * @return the string representation of the DN component. */ public String toString() { - StringBuffer buf = new StringBuffer( m_type[0] + "=" + m_value[0] ); - - for ( int i = 1; i < m_type.length; i++ ) { - buf.append( " + " + m_type[i] + "=" + m_value[i] ); + StringBuffer buf = new StringBuffer(); + + for ( int i = 0; m_type != null && i < m_type.length; i++ ) { + if ( i != 0) { + buf.append(" + "); + } + buf.append( m_type[i] + "=" + m_value[i]); } return buf.toString(); diff --git a/directory/java-sdk/ldapsp/com/netscape/jndi/ldap/LdapReferralException.java b/directory/java-sdk/ldapsp/com/netscape/jndi/ldap/LdapReferralException.java index 946d34b05a74..78e102239cec 100644 --- a/directory/java-sdk/ldapsp/com/netscape/jndi/ldap/LdapReferralException.java +++ b/directory/java-sdk/ldapsp/com/netscape/jndi/ldap/LdapReferralException.java @@ -45,12 +45,12 @@ class LdapReferralException extends javax.naming.ldap.LdapReferralException { } public Object getReferralInfo() { - return m_ldapEx.getURLs(); + return m_ldapEx.getURLs()[m_referralIdx].toString(); } public Context getReferralContext() throws NamingException{ Hashtable env = m_srcCtx.getEnv().getAllProperties(); - env.put(ContextEnv.P_PROVIDER_URL, m_ldapEx.getURLs()[m_referralIdx]); + env.put(ContextEnv.P_PROVIDER_URL, m_ldapEx.getURLs()[m_referralIdx].toString()); return new LdapContextImpl(env); } @@ -59,7 +59,8 @@ class LdapReferralException extends javax.naming.ldap.LdapReferralException { } public Context getReferralContext(Hashtable env, Control[] reqCtls) throws NamingException{ - env.put(ContextEnv.P_PROVIDER_URL, m_ldapEx.getURLs()[m_referralIdx]); + + env.put(ContextEnv.P_PROVIDER_URL, m_ldapEx.getURLs()[m_referralIdx].toString()); if (reqCtls != null) { env.put(ContextEnv.P_CONNECT_CTRLS, reqCtls); }