зеркало из https://github.com/mozilla/gecko-dev.git
Updtates for LDAPJDK 4.14
This commit is contained in:
Родитель
dfba87f614
Коммит
1e9dcafbfa
|
@ -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();
|
||||
|
|
|
@ -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; <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.
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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" } );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 : "********") + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
@ -156,12 +117,59 @@ public final class DN implements Serializable {
|
|||
/* reverse the RDNs order */
|
||||
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 = {',', '+', '"', '\\', '<', '>', ';'};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 + ' ' );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <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] );
|
||||
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче