Updtates for LDAPJDK 4.14

This commit is contained in:
miodrag%netscape.com 2001-03-28 15:45:58 +00:00
parent dfba87f614
commit 1e9dcafbfa
18 changed files with 480 additions and 292 deletions

View File

@ -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();

View File

@ -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,6 +74,11 @@ 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
@ -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; <CODE>null</CODE> 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.
@ -241,13 +266,14 @@ class LDAPConnThread extends Thread {
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,6 +634,11 @@ 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) {
@ -599,6 +650,22 @@ class LDAPConnThread extends Thread {
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();

View File

@ -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 <CODE>LDAPv2.BIND</CODE> option to null.
* <P>By default, the value of this option is <CODE>null</CODE>.</TD></TR>
* <TR VALIGN=BASELINE><TD>
* <CODE>LDAPv2.BIND>/CODE></TD>
* <CODE>LDAPv2.BIND</CODE></TD>
* <TD><CODE>LDAPBind</CODE></TD>
* <TD>Specifies an object with a class that implements the
* <CODE>LDAPBind</CODE>
@ -4207,7 +4210,8 @@ public class LDAPConnection
* <TD><CODE>Integer</CODE></TD>
* <TD>Specifies the maximum number of search results to accumulate in an
* LDAPSearchResults before suspending the reading of input from the server.
* <P>By default, the value of this option is 100.</TD></TR>
* <P>By default, the value of this option is 100. The value 0 means there
* is no limit.</TD></TR>
* </TABLE><P>
* @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 <CODE>LDAPv2.BIND</CODE> option to null.
* <P>By default, the value of this option is <CODE>null</CODE>.</TD></TR>
* <TR VALIGN=BASELINE><TD>
* <CODE>LDAPv2.BIND>/CODE></TD>
* <CODE>LDAPv2.BIND</CODE></TD>
* <TD><CODE>LDAPBind</CODE></TD>
* <TD>Specifies an object with a class that implements the
* <CODE>LDAPBind</CODE>
@ -4405,7 +4409,8 @@ public class LDAPConnection
* <TD><CODE>Integer</CODE></TD>
* <TD>Specifies the maximum number of search results to accumulate in an
* LDAPSearchResults before suspending the reading of input from the server.
* <P>By default, the value of this option is 100.</TD></TR>
* <P>By default, the value of this option is 100. The value 0 means there
* is no limit.</TD></TR>
* </TABLE><P>
* @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.

View File

@ -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;
}
}

View File

@ -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) {
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
}
mq2.reset();
notifyAll(); // notify for mq2
notifyAll(); // notify this mq
}
notifyAll(); // notify this mq
}

View File

@ -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" } );
}
/**

View File

@ -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 <CODE>LDAPSearchConstraints</CODE> 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 <CODE>LDAPConnection.getOption()</CODE>
* @deprecated Use <CODE>LDAPConnection.setOption()</CODE>
*/
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 <CODE>LDAPConnection.setOption()</CODE>
* @deprecated Use <CODE>LDAPConnection.getOption()</CODE>
*/
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();

View File

@ -85,9 +85,9 @@ 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();
}
}
@ -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

View File

@ -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) {
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 : "********") + "}";
}
/**

View File

@ -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(),

View File

@ -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<ESCAPED_CHAR.length; j++) {
if (c == ESCAPED_CHAR[j]) {
i++;
rbuffer.append(buffer.charAt(i));
break;
}
}
} else if (buffer.charAt(i) == '"') {
// this is the second "
if (openQuotes) {
openQuotes = false;
} else
// this is the first "
openQuotes = true;
} else if (buffer.charAt(i) == ',') {
// the content is not within the double quotes
if (!openQuotes) {
rbuffer.setLength(rbuffer.length()-1);
if (!appendRDN(rbuffer))
return;
rbuffer = new StringBuffer();
}
}
i++;
}
// if we cannot find the second ", then the DN is not in proper format
if (openQuotes) {
m_rdns.removeAllElements();
return;
}
if (!appendRDN(rbuffer))
return;
} else if (dn.indexOf('/') != -1) { /* OSF */
if (neutralDN.indexOf(',') != -1 || neutralDN.indexOf(';') != -1) {
parseRDNs(neutralDN, dn, ",;");
}
else if (dn.indexOf('/') != -1) { /* OSF */
m_dnType = OSF;
StringTokenizer st = new StringTokenizer(dn, "/");
Vector rdns = new Vector();
@ -157,11 +118,58 @@ public final class DN implements Serializable {
for (int i = rdns.size() - 1; i >= 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 = {',', '+', '"', '\\', '<', '>', ';'};
}

View File

@ -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;

View File

@ -18,6 +18,7 @@
* Rights Reserved.
*
* 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 + ' ' );
}
}

View File

@ -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,45 +99,100 @@ 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;
/**
* 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;
}
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 );
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;
}
}
// 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();
}
next_close_q = next_open_q > -1 ? str.indexOf( '"', next_open_q + 1 )
: -1;
/**
* 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 -1;
return true;
}
/**
@ -162,7 +221,10 @@ public final class RDN implements java.io.Serializable {
* @deprecated use <code>getTypes()</code> 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 <code>getValues()</code> 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] );
StringBuffer buf = new StringBuffer();
for ( int i = 1; i < m_type.length; i++ ) {
buf.append( " + " + m_type[i] + "=" + m_value[i] );
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();

View File

@ -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);
}