Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

LDAPConnection from PoolManager fails to reconnect when connection is dropped by LDAP server

1,065 views
Skip to first unread message

shuhchang

unread,
Jan 4, 2006, 11:40:31 AM1/4/06
to
Hi,

I use PoolManager to help create and manage a group of LDAPConnection
objects for better LDAP performance. For example, to create two physical
connections with five LDAPConnection objects sharing each physical
connection, you can do:

PoolManager ldapPool = new PoolManager(ldapHost,ldapPort,2,5,null);

To use an LDAPConnection object for accessing LDAP server, you can get it
from the PoolManager:

LDAPConnection lc = ldapPool.getBoundConnection(loginDN,
password.getBytes("UTF8"));

After you are done with the LDAPConnection, lc in our example, you can
return (free) that LDAPConnection object back to the PoolManager for later
use:

ldapPool.makeConnectionAvailable(lc);

This simple scheme works well under normal condition, i.e. when the
LDAPConnection is always alive. If the LDAP server, for some reason, drops
the connection, the PoolManager would shut down the physical connection,
making the shared LDAPConnection for that physical connection inactive.
However, even if the LDAPConnection objects managed by the PoolManager are
no longer active, you can still get them from the PoolManager. If you use
that inactive LDAPConnection object, it would try to wait (forever) for
the incoming message, and therefore would hang.

The issue here is that the PoolManager only provides a very simple API.
Basically, it just has getBoundConnection and makeConnectionAvailable. It
does not provide the capability for a proper reconnection once the
LDAPConnection managed by PoolManager becomes inactive.

Is there anyway that we can improve PoolManager to properly handle the
dropped connection for the LDAPConnection objects that it manages?

Thanks very much.

Regards,
Shuh


@novell.com Susan Perrin

unread,
Jan 4, 2006, 1:13:23 PM1/4/06
to
Hi

You can call isConnectionAlive method on the connection to make sure it's
active. The only way to test that the connection is valid is to write to
it, and isConnectionAlive sends a request to the server using a bogus
extension, just to generate an ldap request.

You mention that your connection is hanging indefinately. I'd expect that
calling a write attempt on the connection should generate an exception if
the connection is broken, and that isConnectionAlive should return false.
It does for me if I just disable nldap on my server while holding a
connection open on the client.

Can you tell me how the disconnect has occurred?

One of the parameters you can pass to a PoolManager is a socket factory, so
you could write your own where you set the parameters on the underlying
socket, such as setSoTimeout, setSoLinger etc.

Thank you
Susan


shuhchang

unread,
Jan 4, 2006, 4:07:28 PM1/4/06
to
I forgot to mention that I am using the latest binary
novell-jldap-devel-2005.10.03-1netware_windows.exe
which has the time stamp:
09/30/2005 12:57 PM 439,100 ldap.jar

I am using the JLDAP to test against Active Directory.

According to the latest JLDAP Change Note, it's supposed to have resolved
the connection issue. However, I am still experiencing this issue. Below
is a debug trace through a very simple scenario that can reproduce this
problem. I also added comments in the log file to illustrate what the code
is doing.

Test Pseudo Code:
================

// Use PoolManager to create two physical connections and each has only
one LDAPConnection
// object. The LDAPConnection in Connection(1) is used for LDAP search,
and will be timeout
// after five minutes. The LDAPConenction in Connection(2) is not used
for LDAP query, and
// therefore will be timeout after two minutes. These two timeouts have
been set at the
// LDAP server.
PoolManager ldapPool = PoolManager ldapPool = new
PoolManager(ldapHost,ldapPort,2,1,null);

for (int i = 0; i < 2; i++) {


LDAPConnection lc = ldapPool.getBoundConnection(loginDN,
password.getBytes("UTF8"));

LDAPSearchResults searchResults =
lc.search( searchBase, searchScope, searchFilter, null, false);
ldapPool.makeConnectionAvailable(lc);
pause(); // wait for more than five minutes so that physical
Connection(2) would
// shut down after two minutes, and physical Connection (1)
would shut
// down after five minutes.
}


Debug Log File:
==============
[Note: comments are in square brackets [].]

[To create Physical Connetion(1)...]


13:45:04.758 traceAPIRequests: LDAPConstraints(1): Created, follow
referrals = false
13:45:04.758 traceAPIRequests: LDAPSearchConstraints(1): Created
13:45:04.758 traceAPIRequests: LDAPConnection(1): Created
13:45:04.808 traceMessages: Connection(1): Created
13:45:04.808 traceAPIRequests: LDAPConnection(1): connect(myHost, 389)
13:45:04.808 traceMessages: Connection(1): destroyClone(true)
13:45:04.808 traceMessages: Connection(1): connect(myHost,389)
13:45:04.808 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(-2) count 1
13:45:04.868 traceMessages: Connection(1): waiting for reader thread to
start
13:45:04.868 traceMessages: Connection(1): reader: thread starting:
Thread[Thread-0,5,main]
13:45:04.878 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(-2) count 0
13:45:04.878 traceMessages: Connection(1): connect: setup complete

[Physical Connetion(1) was created...]

[To create Physical Connetion(2)...]


13:45:04.878 traceAPIRequests: LDAPConstraints(2): Created, follow
referrals = false
13:45:04.878 traceAPIRequests: LDAPSearchConstraints(2): Created
13:45:04.878 traceAPIRequests: LDAPConnection(2): Created
13:45:04.878 traceMessages: Connection(2): Created
13:45:04.878 traceAPIRequests: LDAPConnection(2): connect(myHost, 389)
13:45:04.878 traceMessages: Connection(2): destroyClone(true)
13:45:04.878 traceMessages: Connection(2): connect(myHost,389)
13:45:04.878 traceBindSemaphore: Connection(2): Acquired Socket Write
Semaphore(-2) count 1
13:45:04.888 traceMessages: Connection(2): waiting for reader thread to
start
13:45:04.888 traceMessages: Connection(2): reader: thread starting:
Thread[Thread-1,5,main]
13:45:04.898 traceBindSemaphore: Connection(2): Free'd Socket Write
Semaphore(-2) count 0
13:45:04.898 traceMessages: Connection(2): connect: setup complete


[Physical Connetion(2) was created...]

[Got Physical Connection(1).LDAPConnection(1) from
PoolManager.getBoundConnection().]

[lc status: bound/connected/connectionAlive = true/true/true]

[To use Physical Connection(1).LDAPConnection(1) to bind...]


13:45:04.898 traceAPIRequests: LDAPConnection(1): bind("cn=Shuh
Chang,cn=Users,dc=testnode,dc=com")
13:45:04.968 traceAPIRequests: Creating [UNIVERSAL 16] SEQUENCE: {
[UNIVERSAL 2] INTEGER: 1,

[APPLICATION 0] SEQUENCE: { [UNIVERSAL 2] INTEGER: 3, [UNIVERSAL 4] OCTET
STRING: cn=Shuh Chang,cn=Users,dc=testnode,dc=com, [0] OCTET STRING:
secret } }
13:45:04.968 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(1) count 1
13:45:04.978 traceMessages: MessageAgent(1): Created
13:45:04.978 traceMessages: LDAPResponseQueue(1): Created
13:45:04.988 traceMessages: Message(1): Created with mslimit 0
13:45:04.988 traceMessages: MessageAgent(1): sendMessage: Added new
Message(1)
13:45:04.988 traceMessages: MessageAgent(1): Queue Status
13:45:04.988 traceMessages: MessageAgent(1): 0.: Message(1)
13:45:04.988 traceMessages: Message(1): Sending request to Connection(1):
13:45:04.988 traceMessages: Connection(1): Writing Message(1)
13:45:04.988 traceRawInput: Connection(1): RawWrite: [UNIVERSAL 16]
SEQUENCE: { [UNIVERSAL 2]

INTEGER: 1, [APPLICATION 0] SEQUENCE: { [UNIVERSAL 2] INTEGER: 3,
[UNIVERSAL 4] OCTET STRING:

cn=Shuh Chang,cn=Users,dc=testnode,dc=com, [0] OCTET STRING: secret } }
13:45:04.988 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(1) count 2
13:45:04.988 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(1) count 1
13:45:04.988 traceAPIRequests: LDAPResponseQueue(1): getResponse(null)
13:45:04.988 traceMessages: MessageAgent(1): getLDAPMessage(null), 1
messages active
13:45:04.988 traceMessages: MessageAgent(1): getLDAPMessage: Look for any
reply, 1 messages

active
13:45:04.988 traceMessages: Message(1): No replies queued for message
13:45:04.988 traceMessages: MessageAgent(1): getLDAPMessage: no messages
queued for Message(1)
13:45:04.988 traceMessages: MessageAgent(1): getLDAPMessage: waiting for
incoming messages
13:45:04.988 traceMessages: RfcLDAPMessage: input message w/tag 1
13:45:05.018 traceRawInput: Connection(1): RawRead: [UNIVERSAL 16]
SEQUENCE: { [UNIVERSAL 2]

INTEGER: 1, [APPLICATION 1] SEQUENCE: { [UNIVERSAL 10] ENUMERATED: 0,
[UNIVERSAL 4] OCTET STRING:

, [UNIVERSAL 4] OCTET STRING: } }
13:45:05.018 traceMessages: Connection(1): reader: queue response to
message(1)
13:45:05.018 traceMessages: Message(1): Queued LDAPResult (1 in queue),
message complete stopping

timer, status 0
13:45:05.018 traceMessages: Message(1): Bind properties found
13:45:05.018 traceMessages: Message(1): Bind status success
13:45:05.018 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(1) count 0
13:45:05.018 traceMessages: Message(1): Sleepers Awake, MessageAgent(1):
13:45:05.018 traceMessages: MessageAgent(1): getLDAPMessage: wake up from
wait
13:45:05.018 traceMessages: MessageAgent(1): getLDAPMessage: Look for any
reply, 1 messages

active
13:45:05.018 traceMessages: Message(1): Got reply from queue(0 remaining
in queue)
13:45:05.018 traceMessages: Connection(1): Removed Message(1)
13:45:05.018 traceMessages: MessageAgent(1): getLDAPMessage: cleanup
Message(1)
13:45:05.018 traceMessages: Message(1): Abandon request, complete=true,
bind=true,

informUser=false, waitForReply=true
13:45:05.018 traceMessages: Message(1): Sleepers Awake, MessageAgent(1):
13:45:05.018 traceMessages: Message(1): cleanup
13:45:05.018 traceMessages: Connection(1): Removing Message(1) - not found
13:45:05.018 traceMessages: MessageAgent(1): getLDAPMessage: Return
response to Message(1)
13:45:05.018 traceMessages: MessageAgent(1): Queue Status
13:45:05.018 traceMessages: MessageAgent(1): No messages queued
13:45:05.028 traceMessages: LDAPResponse: message(1) result code 0
13:45:05.038 traceAPIRequests: Creating LDAPExtendedRequest(2): [UNIVERSAL
16] SEQUENCE: {

[UNIVERSAL 2] INTEGER: 2, [APPLICATION 23] SEQUENCE: { [0] OCTET STRING:
0.0.0.0 } }
13:45:05.038 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(2) count 1
13:45:05.038 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(2) count 0
13:45:05.038 traceMessages: RfcLDAPMessage: input message w/tag 24
13:45:05.038 traceRawInput: Connection(1): RawRead: [UNIVERSAL 16]
SEQUENCE: { [UNIVERSAL 2]

INTEGER: 2, [APPLICATION 24] SEQUENCE: { [UNIVERSAL 10] ENUMERATED: 2,
[UNIVERSAL 4] OCTET

STRING: , [UNIVERSAL 4] OCTET STRING: 0000203D: LdapErr: DSID-0C090BAC,
comment: Unknown extended

request OID, data 0, vece } }
13:45:05.038 traceAPIRequests: Creating LDAPExtendedRequest(3): [UNIVERSAL
16] SEQUENCE: {

[UNIVERSAL 2] INTEGER: 3, [APPLICATION 23] SEQUENCE: { [0] OCTET STRING:
0.0.0.0 } }
13:45:05.038 traceMessages: Connection(1): reader: message(2) not found,
discarding reply
13:45:05.038 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(3) count 1
13:45:05.038 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(3) count 0


[To use Physical Connection(1).LDAPConnection(1) to search...]


13:45:05.038 traceAPIRequests: LDAPConnection(1):

search("ou=device,dc=testnode,dc=com",2,"(my-DevUid=*)")
13:45:05.038 traceMessages: RfcLDAPMessage: input message w/tag 24
13:45:05.038 traceRawInput: Connection(1): RawRead: [UNIVERSAL 16]
SEQUENCE: { [UNIVERSAL 2]

INTEGER: 3, [APPLICATION 24] SEQUENCE: { [UNIVERSAL 10] ENUMERATED: 2,
[UNIVERSAL 4] OCTET

STRING: , [UNIVERSAL 4] OCTET STRING: 0000203D: LdapErr: DSID-0C090BAC,
comment: Unknown extended

request OID, data 0, vece } }
13:45:05.038 traceMessages: Connection(1): reader: message(3) not found,
discarding reply
13:45:05.058 traceAPIRequests: Creating LDAPSearchRequest(4): [UNIVERSAL
16] SEQUENCE: {

[UNIVERSAL 2] INTEGER: 4, [APPLICATION 3] SEQUENCE: { [UNIVERSAL 4] OCTET
STRING:

ou=device,dc=testnode,dc=com, [UNIVERSAL 10] ENUMERATED: 2, [UNIVERSAL 10]
ENUMERATED: 0,

[UNIVERSAL 2] INTEGER: 1000, [UNIVERSAL 2] INTEGER: 0, [UNIVERSAL 1]
BOOLEAN: false, [7] OCTET

STRING: my-DevUid, [UNIVERSAL 16] SEQUENCE OF: { } } }
13:45:05.058 traceMessages: MessageAgent(2): Created
13:45:05.058 traceMessages: LDAPSearchQueue(2): Created
13:45:05.068 traceMessages: Message(4): Created with mslimit 0
13:45:05.068 traceMessages: MessageAgent(2): sendMessage: Added new
Message(4)
13:45:05.068 traceMessages: MessageAgent(2): Queue Status
13:45:05.068 traceMessages: MessageAgent(2): 0.: Message(4)
13:45:05.068 traceMessages: Message(4): Sending request to Connection(1):
13:45:05.068 traceMessages: Connection(1): Writing Message(4)
13:45:05.068 traceRawInput: Connection(1): RawWrite: [UNIVERSAL 16]
SEQUENCE: { [UNIVERSAL 2]

INTEGER: 4, [APPLICATION 3] SEQUENCE: { [UNIVERSAL 4] OCTET STRING:
ou=device,dc=testnode,dc=com,

[UNIVERSAL 10] ENUMERATED: 2, [UNIVERSAL 10] ENUMERATED: 0, [UNIVERSAL 2]
INTEGER: 1000,

[UNIVERSAL 2] INTEGER: 0, [UNIVERSAL 1] BOOLEAN: false, [7] OCTET STRING:
my-DevUid, [UNIVERSAL

16] SEQUENCE OF: { } } }
13:45:05.068 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(4) count 1
13:45:05.068 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(4) count 0
13:45:05.068 traceMessages: RfcLDAPMessage: input message w/tag 5
13:45:05.068 traceRawInput: Connection(1): RawRead: [UNIVERSAL 16]
SEQUENCE: { [UNIVERSAL 2]

INTEGER: 4, [APPLICATION 5] SEQUENCE: { [UNIVERSAL 10] ENUMERATED: 0,
[UNIVERSAL 4] OCTET STRING:

, [UNIVERSAL 4] OCTET STRING: } }
13:45:05.068 traceMessages: Connection(1): reader: queue response to
message(4)
13:45:05.068 traceMessages: Message(4): Queued LDAPResult (1 in queue),
message complete stopping

timer, status 0
13:45:05.068 traceMessages: LDAPSearchResults(1): Object created, batch
size 1, hops 10
13:45:05.068 traceMessages: Message(4): Sleepers Awake, MessageAgent(2):
13:45:05.068 traceAPIRequests: LDAPSearchQueue(2): getResponse(null)
13:45:05.068 traceMessages: MessageAgent(2): getLDAPMessage(null), 1
messages active
13:45:05.068 traceMessages: MessageAgent(2): getLDAPMessage: Look for any
reply, 1 messages

active
13:45:05.068 traceMessages: Message(4): Got reply from queue(0 remaining
in queue)
13:45:05.068 traceMessages: Connection(1): Removed Message(4)
13:45:05.068 traceMessages: MessageAgent(2): getLDAPMessage: cleanup
Message(4)
13:45:05.068 traceMessages: Message(4): Abandon request, complete=true,
bind=false,

informUser=false, waitForReply=true
13:45:05.068 traceMessages: Message(4): Sleepers Awake, MessageAgent(2):
13:45:05.068 traceMessages: Message(4): cleanup
13:45:05.068 traceMessages: Connection(1): Removing Message(4) - not found
13:45:05.068 traceMessages: MessageAgent(2): getLDAPMessage: Return
response to Message(4)
13:45:05.068 traceMessages: MessageAgent(2): Queue Status
13:45:05.068 traceMessages: MessageAgent(2): No messages queued
13:45:05.068 traceMessages: LDAPSearchResults(1): read
LDAPResponse@147c5fc, result 0
13:45:05.068 traceMessages: LDAPSearchResults(1): checking for done
13:45:05.088 traceMessages: LDAPSearchResults(1): Search completed, all
responses processed
13:45:05.088 traceMessages: LDAPSearchResults(1): hasMoreElements: returns
false, enumeration

status , entryIdx=0, entryCnt=0, referIdx=0, referCnt=0
13:45:05.088 traceMessages: LDAPSearchResults(1): hasMoreElements: returns
false, enumeration

status , entryIdx=0, entryCnt=0, referIdx=0, referCnt=0


[Waiting for 2 minutes...]


13:47:35.485 traceMessages: Connection(2): Connection lost waiting for
results from myHost:389,

clientActive=true
java.io.EOFException: BERDecoder: decode: EOF in Identifier
13:47:35.505 traceMessages: Message(1): finalize
13:47:35.505 traceMessages: Message(1): cleanup
13:47:35.535 traceMessages: new LDAPException(Result=91) Connection lost
waiting for results from

myHost:389
13:47:35.545 traceMessages: InterThreadException created with msg "Connect
Error" and code 91
13:47:35.545 traceMessages: InterThreadException has rootException -
java.io.EOFException:

BERDecoder: decode: EOF in Identifier
13:47:35.545 traceMessages: Connection(2): reader: connection shutdown
13:47:35.545 traceMessages: Connection(2): shutdown: Shutting down
connection - reader: thread

stopping
13:47:35.545 traceMessages: Connection(2): Shutdown no messages to remove
13:47:35.545 traceBindSemaphore: Connection(2): Acquired Socket Write
Semaphore(-3) count 1
13:47:35.545 traceBindSemaphore: Connection(2): Free'd Socket Write
Semaphore(-3) count 0
13:47:35.545 traceMessages: Connection(2): reader: thread terminated


[2 minutes is up. Physical Connection(2) was shut down...]

[Continue to wait...]


13:49:35.497 traceMessages: Connection(1): Connection lost waiting for
results from myHost:389,

clientActive=true
java.io.EOFException: BERDecoder: decode: EOF in Identifier
13:49:35.497 traceMessages: new LDAPException(Result=91) Connection lost
waiting for results from

myHost:389
13:49:35.497 traceMessages: InterThreadException created with msg "Connect
Error" and code 91
13:49:35.497 traceMessages: InterThreadException has rootException -
java.io.EOFException:

BERDecoder: decode: EOF in Identifier
13:49:35.497 traceMessages: Connection(1): reader: connection shutdown
13:49:35.497 traceMessages: Connection(1): shutdown: Shutting down
connection - reader: thread

stopping
13:49:35.507 traceMessages: Connection(1): Shutdown no messages to remove
13:49:35.507 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(-3) count 1
13:49:35.507 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(-3) count 0
13:49:35.507 traceMessages: Connection(1): reader: thread terminated


[5 minutes is up. Physical Connection(1) was also shut down...]

[Got Physical Connection(1).LDAPConnection(1) from
PoolManager.getBoundConnection().]
[lc status: bound/connected/connectionAlive = false/false/false]

[To use Physical Connection(1).LDAPConnection(1) to search...]


13:50:07.253 traceAPIRequests: LDAPConnection(1):

search("ou=device,dc=testnode,dc=com",2,"(my-DevUid=*)")
13:50:07.253 traceAPIRequests: Creating LDAPSearchRequest(5): [UNIVERSAL
16] SEQUENCE: {

[UNIVERSAL 2] INTEGER: 5, [APPLICATION 3] SEQUENCE: { [UNIVERSAL 4] OCTET
STRING:

ou=device,dc=testnode,dc=com, [UNIVERSAL 10] ENUMERATED: 2, [UNIVERSAL 10]
ENUMERATED: 0,

[UNIVERSAL 2] INTEGER: 1000, [UNIVERSAL 2] INTEGER: 0, [UNIVERSAL 1]
BOOLEAN: false, [7] OCTET

STRING: my-DevUid, [UNIVERSAL 16] SEQUENCE OF: { } } }
13:50:07.253 traceMessages: MessageAgent(3): Created
13:50:07.253 traceMessages: LDAPSearchQueue(3): Createdread: ? hex value:
-1
13:50:07.253 traceMessages: Message(5): Created with mslimit 0
13:50:07.253 traceMessages: MessageAgent(3): sendMessage: Added new
Message(5)
13:50:07.253 traceMessages: MessageAgent(3): Queue Status
13:50:07.253 traceMessages: MessageAgent(3): 0.: Message(5)
13:50:07.253 traceMessages: Message(5): Sending request to Connection(1):
13:50:07.253 traceMessages: Connection(1): Writing Message(5)
13:50:07.253 traceRawInput: Connection(1): RawWrite: [UNIVERSAL 16]
SEQUENCE: { [UNIVERSAL 2]

INTEGER: 5, [APPLICATION 3] SEQUENCE: { [UNIVERSAL 4] OCTET STRING:
ou=device,dc=testnode,dc=com,

[UNIVERSAL 10] ENUMERATED: 2, [UNIVERSAL 10] ENUMERATED: 0, [UNIVERSAL 2]
INTEGER: 1000,

[UNIVERSAL 2] INTEGER: 0, [UNIVERSAL 1] BOOLEAN: false, [7] OCTET STRING:
my-DevUid, [UNIVERSAL

16] SEQUENCE OF: { } } }
13:50:07.263 traceBindSemaphore: Connection(1): Acquired Socket Write
Semaphore(5) count 1
13:50:07.263 traceMessages: Connection(1): I/O Exception on hostmyHost:389
java.io.IOException:

Output stream not initialized
13:50:07.263 traceBindSemaphore: Connection(1): Free'd Socket Write
Semaphore(5) count 0
13:50:07.263 traceMessages: LDAPSearchResults(2): Object created, batch
size 1, hops 10
13:50:07.263 traceAPIRequests: LDAPSearchQueue(3): getResponse(null)
13:50:07.273 traceMessages: MessageAgent(3): getLDAPMessage(null), 1
messages active
13:50:07.273 traceMessages: MessageAgent(3): getLDAPMessage: Look for any
reply, 1 messages

active
13:50:07.283 traceMessages: Message(5): No replies queued for message
13:50:07.283 traceMessages: MessageAgent(3): getLDAPMessage: no messages
queued for Message(5)
13:50:07.283 traceMessages: MessageAgent(3): getLDAPMessage: waiting for
incoming messages


[LDAPConnection hangs here...]


shuhchang

unread,
Jan 4, 2006, 4:38:36 PM1/4/06
to
Hi Susan,

Thank you very much for your prompt response. Please see below for my
comments.

Shuh

Susan Perrin wrote:

> Hi

> You can call isConnectionAlive method on the connection to make sure it's
> active.

Yes, I did notice that. The log file I just posted a few minutes ago did
show the three statuses of the LDAPConnection. It has
LDAPConnection: bound/connected/connectionAlive = true/true/true
when the Connection is still valid, and it has
LDAPConnection: bound/connected/connectionAlive = false/false/false
when the Connection is shut down.

> You mention that your connection is hanging indefinately. I'd expect that
> calling a write attempt on the connection should generate an exception if
> the connection is broken, and that isConnectionAlive should return false.

This is true as mentioned above. However, the write is done within the
Message when you try to do a regular LDAP query. This can be witnessed in
the log file that I attached in the previous posting.

> Can you tell me how the disconnect has occurred?

Yes. As I demonstrated in the log file in the posting I just made, the
disconnect occurs when the LDAP server disconnects while the client
LDAPConnection is still managed by PoolManager.

> One of the parameters you can pass to a PoolManager is a socket factory, so
> you could write your own where you set the parameters on the underlying
> socket, such as setSoTimeout, setSoLinger etc.

I did notice that I could set my own socket factory. However, that doesn't
seem to solve the reconnect problem that PoolManager has. The issue is
that PoolManager is managing all the LDAPConnection objects. The client
only get and return the LDAPConnection object from/to the PoolManager. If
the conenction is dropped by the LDAP server, then PoolManager would need
to make sure that it reconnects.

From the client side, I only have the LDAPCOnnection object obtained from
PoolManager. Of course, I could check its bound/connected/connectionAlive
status as stated above. However, even if I detected that
bound/connected/connectionAlive is no longer active (false), I still
cannot reconnect using just the LDAPConnection object. There is no
reconnect() method available in the LDAPConnection object. That's why I
thought the reconnect would have to be done within PoolManager - either be
done automatically or provide a reconnect() method so that I can say
something like:

ldapPool.reconnect(lc);

I am not sure how that reconnect() method should be done within
PoolManager though. Just discard the old one and re-create a new one? Or
something better to re-use the existing but disconnected LDAPCOnnection
object.

On the other hand, if I just discard the inactive LDAPConnection object
and create a new one, then doesn't it beat the prupose of having
PoolManager to handle the LDAPConnection objects? Furthermore, if I did
re-create a new LDAPConnection object, how do I turn it over to the
PoolManager so that it can continue to manage it for me?

> Thank you
> Susan

Once again, thanks for your reply.

Shuh


@novell.com Susan Perrin

unread,
Jan 4, 2006, 5:08:04 PM1/4/06
to
Hi

It is possible to set the AD ldap timeout to 0 so that it doesn't drop the
connections. It's also possible to set the eDirectory idle timeout to 0,
which I recommend when you're using connection pooling. The point of
connection pooling is to maintain an array of active (and mostly idle)
connections. If the server times them out after some amount of time, this
is obviously a problem.

You are correct that the connection pool class in the jldap sdk is
simplistic and does not test for broken connections nor attempt to
reconnect. However, I'm not convinced that it should, although I will
certainly run this past the engineers responsible for the class. It seems
to me that this incurrs overhead for everybody when the situation you
describe is in fact fairly rare.

The sources to the classes are available at openldap.org, and certainly you
can take a look at the source to the class and modify it if you like.
However, I'm still not clear (and be patient with me, this is probably my
blind spot) why it makes a difference whether the connection is checked for
isConnectionAlive from within the pool class or by the client who has
requested the connection. The connections maintained by the pool class are
just LDAPConnection objects with some additional properties. What you've
got is either a cloned or separate LDAPConnection, and I don't understand
why you can't simply call connect and bind on the connection (if it's dead)
and pass it back to the pool. Please explain, and I'll set up the condition
you describe to reproduce.

Thanks
Susan


shuhchang

unread,
Jan 4, 2006, 6:57:41 PM1/4/06
to
Please see comments below. Thanks.

Shuh

Susan Perrin wrote:

> Hi

> It is possible to set the AD ldap timeout to 0 so that it doesn't drop the
> connections. It's also possible to set the eDirectory idle timeout to 0,
> which I recommend when you're using connection pooling. The point of
> connection pooling is to maintain an array of active (and mostly idle)
> connections. If the server times them out after some amount of time, this
> is obviously a problem.

Yes, I have contemplated setting the LDAP server parameters so that they
do not timeout. However, this proves not a viable solution for us. We
cannot simply set all the LDAP servers to never timeout. It would kill the
LDAP servers pretty quickly. Just for an easy reason, any simple DOS
attach can quickly bring your LDAP servers to their knee. That's why I
would have to properly handle the timeout on the client side.

> You are correct that the connection pool class in the jldap sdk is
> simplistic and does not test for broken connections nor attempt to
> reconnect. However, I'm not convinced that it should, although I will
> certainly run this past the engineers responsible for the class. It seems
> to me that this incurrs overhead for everybody when the situation you
> describe is in fact fairly rare.

The broken connections are way of life that we have to deal with when
developing server side software. There are many reasons why a connection
would break. Other then the timeouts imposed by the LDAP servers described
above, a simple temporary cable disconnection could also result in the
same thing. There are many other potential possibilities that a connection
would break and we have to deal with them. For this reason, I think that,
rather than fairly rare, this detection on disconnection is required for
all serious LDAP developers. Therefore, the reconnection issue would have
to be dealt with. And where is the best place to handle this? Well, from
the software development point of view (modularity, maintenability, etc.),
it would be best handled in PoolManager.

> The sources to the classes are available at openldap.org, and certainly you
> can take a look at the source to the class and modify it if you like.

I would consider this approach as the last resort, but yes, I have
downloaded the source from OpenLDAP.

> However, I'm still not clear (and be patient with me, this is probably my
> blind spot) why it makes a difference whether the connection is checked for
> isConnectionAlive from within the pool class or by the client who has
> requested the connection. The connections maintained by the pool class are
> just LDAPConnection objects with some additional properties. What you've
> got is either a cloned or separate LDAPConnection, and I don't understand
> why you can't simply call connect and bind on the connection (if it's dead)
> and pass it back to the pool. Please explain, and I'll set up the condition
> you describe to reproduce.

A very good point, and I have tried that. If you do the connect from
outside of PoolManager, you could potentially break PoolManager's
management scheme for LDAPConnection objects. For example, upon detecting
the LDAPConnection lc being inactive, I tried to just call lc.connect()
which requires the ldapHost and ldapPort. Yes, lc is now connected. But
now, how about the bind? Okay, you could try lc.bind(), but that doesn't
work because it complaints about you have to use
ldapPool.getBoundConnection() to bind. (There is an allowedBind
somewhere?) As you can begin to tell, any effort that you try to repair
the connection outside of PoolManager would interfere what PoolManager was
designed to do: manage the LDAPConnection objects for the client software.
The client software should not worry about the LDAPConnection that it
acquires from the PoolManager. Otherwise, you can imagine that you get an
LDAPConnection object from PoolManager, but PoolManager could hand you
either a good one or a broken one. If you are not lucky and get a bad one,
then you would have to repair that connection and step over PoolManager's
toes.

> Thanks
> Susan


@novell.com Susan Perrin

unread,
Jan 4, 2006, 7:15:05 PM1/4/06
to
Hi

> We
> cannot simply set all the LDAP servers to never timeout

Fair enough.

> There are many reasons why a connection
> would break.

Correct, and that could happen after the connection is checked out of the
pool, too, and you are using it. In these cases you need to watch for the
exceptions and handle them.

But I believe from your remarks that checking the isAlive status and
correcting it is a good enhancement request for the pool manager.

> but that doesn't
> work because it complaints about you have to use
> ldapPool.getBoundConnection() to bind.

Ah, my misunderstanding, thank you. It seems very clear to me that even if
the pool manager isn't handling this for you, it shouldn't PREVENT you from
correcting the condition yourself! I'll look into this deeper. Thank you
for the very thorough explanation.

Susan


shuhchang

unread,
Jan 4, 2006, 7:17:30 PM1/4/06
to
shuhchang wrote:

> now, how about the bind? Okay, you could try lc.bind(), but that doesn't
> work because it complaints about you have to use
> ldapPool.getBoundConnection() to bind.

I forgot to attach the actual error messages that JLDAP complaints about
when you try to bind LDAPConnection, lc, outside of PoolManager:

lc.bind(ldapVersion,loginDN, password.getBytes("UTF8"));

Error: LDAPLocalException: Cannot bind. Use
PoolManager.getBoundConnection() (82) Local Error
lc status: bound/connected/connectionAlive = false/true/true

[So the lc was connected, but is not allowed to bind.]

Error: LDAPException: Operations Error (1) Operations Error
LDAPException: Server Message: 00000000: LdapErr: DSID-0C0905FF, comment:
In order to perform this operation a successful bind must be completed on
the connection., data 0, vece

[Now, the repaired lc outside of PoolManager is still crippled and cannot
be used because it needs to bind.]

Regards,
Shuh


shuhchang

unread,
Jan 4, 2006, 7:58:57 PM1/4/06
to
Susan Perrin wrote:

> > There are many reasons why a connection
> > would break.

> Correct, and that could happen after the connection is checked out of the
> pool, too, and you are using it. In these cases you need to watch for the
> exceptions and handle them.

> But I believe from your remarks that checking the isAlive status and
> correcting it is a good enhancement request for the pool manager.

Yes, I also thought that this migth be just an enhancement on PoolManager.
The thing is that even if I could catch the inactive status of
LDAPConnection object and throw exceptions accordingly, sooner or later,
all the LDAPConnection objects that the PoolManager manages would end up
being all inactive -- meaning dead, and I can no longer use *any*
LDAPConnetion object from PoolManager. This is exactly what happened in my
case. For that reason, I would sincerely consider it more than an
enhancement.

In fact, I had a chance to read some other older issues that other people
submitted in this forum and OpenLDAP forum. Some reported that there is a
NullPointerException exception relating to the JLDAP/connection usage.
Interestingly enough, this is exactly the first innocent but misleading
exception that I saw in my system, and began a long (very long) journey to
uncover the myth of this whole issue. It took me a while to track down
this problem that can surface in many different forms that are not so
obvious at first sight. I believe if this issue is solved, it could also
solve many other seemingly un-related issues. That's just my personal view.

Nonetheless, I really appreciate your attention to this issue. Thank you
so very much for any efforts that you and your engineers would help
resolve this issue. Please do not let this discussion to overshadow the
many other good features and capabilities that JLDAP provides us.

Regards,
Shuh


Jim Willeke

unread,
Jan 5, 2006, 6:26:48 AM1/5/06
to
If you will remember, Susan, we looked into this issue some time back
and were looking for an enhancement to the TCP Socket.

As in this case, the LDAP server is gone, but the TCP session is still
intact.

-jim

@novell.com Susan Perrin

unread,
Jan 5, 2006, 12:12:23 PM1/5/06
to
Shuh

I sent your request to the engineering team responsible for the jldap
classes. I got back this:

The scenario you quoted seems to work well when we tried out here with the
latest code. We created a connection(pool) and when the server drops the
connection (as when timeout happens), the application got bound to the
server quite well without any problem. But I am not very sure about the
application, the client is using. So, if you can get me the sample snippet
the customer is using, that will be very helpful to point out the issue.
Meanwhile, please ask the customer to use the latest 'jldap' source and try
out.

Can you post an example for me to send along?

Thanks

Susan


@novell.com Susan Perrin

unread,
Jan 5, 2006, 5:11:03 PM1/5/06
to
Yes, I think you're right... it's that and also more...

I sent the discussion and logs to the team.

Thank you
Susan


shuhchang

unread,
Jan 5, 2006, 6:08:34 PM1/5/06
to
Susan Perrin wrote:

> Can you post an example for me to send along?

Below is the PMTest.java source code:

PMTest.java:
===========

import com.novell.ldap.LDAPAttribute;
import com.novell.ldap.LDAPAttributeSet;
import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPEntry;
import com.novell.ldap.LDAPException;
import com.novell.ldap.LDAPSearchResults;
import com.novell.ldap.util.Base64;
import com.novell.ldap.connectionpool.PoolManager;
import java.util.Enumeration;
import java.util.Iterator;
import java.io.UnsupportedEncodingException;
import java.io.IOException;

public class PMTest {
int ldapPort = 389; //LDAPConnection.DEFAULT_PORT;
int ldapVersion = LDAPConnection.LDAP_V3;
String searchBase = "cn=Users,dc=testnode,dc=com";
String searchFilter = "(cn=Guest*)";
String ldapHost = "myHost";
String loginDN = "cn=Shuh Chang," + searchBase;
String password = "secret";
int searchScope = LDAPConnection.SCOPE_SUB; // SCOPE_ONE;
PoolManager ldapPool = null;

LDAPConnection lc;

public PMTest() {
try {
ldapPool = new PoolManager(ldapHost,ldapPort,2,1,null);
}
catch( LDAPException e ) {
System.out.println( "Error: " + e.toString() );
}
}

public void searchLDAP() {
try {


LDAPSearchResults searchResults =
lc.search( searchBase,
searchScope,
searchFilter,

null, // return all attributes
false); // return attrs and values

if ( !searchResults.hasMore())
System.out.println("Nothing found.");

while ( searchResults.hasMore()) {
LDAPEntry nextEntry = null;
try {
nextEntry = searchResults.next();
}
catch(LDAPException e) {
System.out.println("Error: " + e.toString());
// Exception is thrown, go for next entry
continue;
}

System.out.println("n" + nextEntry.getDN());
System.out.println(" Attributes: ");

LDAPAttributeSet attributeSet =
nextEntry.getAttributeSet();
Iterator allAttributes = attributeSet.iterator();

while(allAttributes.hasNext()) {
LDAPAttribute attribute =
(LDAPAttribute)allAttributes.next();
String attributeName = attribute.getName();

System.out.println(" " + attributeName);

Enumeration allValues = attribute.getStringValues();

if( allValues != null) {
while(allValues.hasMoreElements()) {
String Value = (String)
allValues.nextElement();
if (Base64.isLDIFSafe(Value)) {
// is printable
System.out.println(" " + Value);
}
else {
// base64 encode and then print out
Value = Base64.encode(Value.getBytes());
System.out.println(" " + Value);
}
}
}
}
}
}
catch( LDAPException e ) {
System.out.println( "Error: " + e.toString() );
}

}

public void getLDAP() {

try {


lc = ldapPool.getBoundConnection(loginDN,
password.getBytes("UTF8"));

inspectLC("from ldapPool.getBoundConnection()");
// If PoolManager works properly,
// I should get good lc statuses.
// If lc is inactive, then let me connect it here.
if (!lc.isConnected() || !lc.isConnectionAlive()) {
lc.connect(ldapHost,ldapPort);
}
// If lc is not bound, then let me bind here.
if (!lc.isBound()) {
// lc.bind(ldapVersion,loginDN, password.getBytes("UTF8"));
//No, cannot bind here. PoolBind is not available to me here.
}
}
catch( LDAPException e ) {
System.out.println( "Error: " + e.toString() );
}
catch( UnsupportedEncodingException e ) {
System.out.println( "Error: " + e.toString() );
}
catch( InterruptedException e ) {
System.out.println( "Error: " + e.toString() );
}
}

public void inspectLC(String msg) {
boolean bound = lc.isBound();
boolean connected = lc.isConnected();
boolean connectionAlive = lc.isConnectionAlive();

System.out.println("inspectLC msg: " + msg);
System.out.println( " ==> lc status:
bound/connected/connectionAlive = " + bound
+ "/" + connected + "/" + connectionAlive);
}

public void freeLDAP() {
ldapPool.makeConnectionAvailable(lc);
}

public String getSearchFilter() {
return searchFilter;
}

private static void pause() {
int i=0;
char c;
try {
// Hit CTRL-Z on PC's to send EOF, CTRL-D on Unix
while ( i != -1 ) {
// Read a character from keyboard
i = System.in.read();
// 1 byte character is returned in int.
// So cast to char
c = (char) i;
System.out.print(c);
}
System.out.println("nDetected EOF...");
} catch (IOException ioe) {
System.out.println( "IO error:" + ioe );
}
}

public static void main( String[] args )
{
PMTest st = new PMTest();
for (int ii = 0; ii < 2; ii++) {
st.getLDAP(); // get lc from PoolManager, mostly
Connection(1).LDAPConnection(1).
st.inspectLC("In loop#" + ii); // inspect lc statuses.
st.searchLDAP(); // Use Connection(1).LDAPConnection(1) to do an
LDAP query.
st.freeLDAP(); // return lc to PoolManager.

System.out.println( "pause... until cntl-z for EOF.");
pause(); // Wait for 2min to timeout physical Connection(2),
// and 5min to timeout physical Connection(1).
// Note that each time a timeout is reached,
// PoolManager reports the shutdown in the log file.
/*
Note: For Active Directory, I set the following parameters:

InitRecvTimeout - This value defines the maximum time in seconds that
a domain controller waits for the client to send the first request after
the domain controller receives a new connection. If the client does not
send the first request in this amount of time, the server disconnects
the client. Set value: 120 seconds
(Physical Connection(2) will timeout by this setting because it was never
used to do the LDAP query after it is created by PoolManager.)

MaxConnIdleTime - The maximum time in seconds that the client can be
idle before the LDAP server closes the connection. If a connection is
idle for more than this time, the LDAP server returns an LDAP disconnect
notification. Set value: 300 seconds
(Physical Connection(1) will timeout by this setting because it was indeed
used to do an LDAP search after it is created by PoolManager.)
*/
st.inspectLC("Outside LC open loop.");
}
System.exit(0);
} // main()

}

shuhchang

unread,
Jan 5, 2006, 6:16:19 PM1/5/06
to
shuhchang wrote:

> Susan Perrin wrote:

> > Can you post an example for me to send along?

The output log file from PMTest.java is too big to fit in the posting
area. If you need the output file, please let me know so that I can send
it directly to you.

Regards,
Shuh


@novell.com Susan Perrin

unread,
Jan 6, 2006, 1:20:14 PM1/6/06
to
No need, thank you. I've forwarded this to the engineering team for you.

Thanks
Susan


@novell.com Susan Perrin

unread,
Jan 9, 2006, 11:48:54 AM1/9/06
to
Bug 142054 - need ability to detect/reconnect/rebind timed out connections
in pool manager has been entered against jldap sdk. Anticipated fix for
next release.

Susan


shuhchang

unread,
Jan 9, 2006, 4:26:59 PM1/9/06
to
Susan Perrin wrote:

> Susan

Hi Susan,

Thanks for the update.

Just as a follow-up on this discussion, below is a bit more detailed
behavior on the disconnected LDAPConnection obejcts managed by
PoolManager. I did not bring up this issue in my prior example and
discussions to keep the point simple and clear.

In the simple example that I posted, I used two physical connections,
Connection(1) and Connection(2), with each having only one LDAPConnection
as shown here (2x1):

ldapPool = new PoolManager(ldapHost,ldapPort,2,1,null);

However, if you created multiple LDAPConnection objects for a physical
connection (a 2x10 for example), and you only use some of the
LDAPConnection objects (3 for example) to do LDAP queries and leave other
LDAPConnection objects unused (the remaining 7 for example), the physical
connection shutdown brought about by the unused LDAPConnection objects
(since they timeout sooner than the used ones) would also bring down the
already-in-use LDAPConnection objects (the 3 in our example). This
scenario might be part of the reason why a seemingly working
LDAPConnection could, all of a sudden, fail miserably! It was brought down
by the unused ones sharing the same physical connection!

This is what makes it a bit more complicated when fixing the PoolManager
to handle the disconnections from the LDAP server.

Thanks.
Shuh


@novell.com Susan Perrin

unread,
Jan 9, 2006, 6:14:47 PM1/9/06
to
>> the physical
>> connection shutdown brought about by the unused LDAPConnection objects
>> (since they timeout sooner than the used ones) would also bring down the
>> already-in-use LDAPConnection objects

Yikes.

I'm looking at poolmanager.java and I'm seeing that these are clones:

// Clone the connections to make all of the sharedConns.
for (int j = 1; j < maxSharedConns; j++)
{
Connection cloneConn = (Connection)conn.clone();
sharedConns.add(cloneConn);
}
availableListOfSharedConnections.add(i, sharedConns);

Probably not a good idea, or at least there should be a way to instantiate
with clones or separate connections to give the user a choice.

Another bug.

Thank you
Susan


shuhchang

unread,
Jan 9, 2006, 7:29:18 PM1/9/06
to
Susan Perrin wrote:

> Yikes.

> Another bug.

> Thank you
> Susan

Hi Susan,

Yikes, indeed.

I actually looked at the PoolManager.java last week and thought that the
cloned LDAPConnection objects might be okay as long as they operate
independently (a wrong assumption).

My earlier attempt to fix the reconnection problem was shown below with
the diff output. The attempt here was to enhance the previous ITS -- JLDAP
Driver Connection Pool problem (ITS#3357). However, I need your engineers'
review on the code fix and make sure that there are no other implications.

On the other hand, the other fix might be more complicated than
illustrated below because of the shutdown mechanism imposed by the JLDAP
driver. This other fix should address, I believe, the "Another bug" that
you alluded.

Regards,
Shuh


$ diff PoolManager.java PoolManager.java-orig
46d45
<
56,58d54
< private String pmHost = null;
< private int pmPort = 389;
< private LDAPSocketFactory pmFactory = null;
86,89c82
< pmHost = host; // keep host for later reconnect if necessary.
< pmPort = port; // keep port for later reconnect if necessary.
< pmFactory = factory; // keep factory for later reconnect if
necessary.
<
---
>
172,197d164
<
< // Do we need to reconnect if connection was previously dropped
< // by LDAP server and it became inactive?
< if (!conn.isConnectionAlive() || !conn.isConnected())
< {
< System.out.println("[SCC]: reconnection in action!");
< try
< {
< conn.disconnect();
< conn.connect(pmHost, pmPort);
< if( pmFactory instanceof LDAPTLSSocketFactory) {
< conn.startTLS();
< }
<
< }catch (LDAPException e)
< {
< // If we get and exception make the shared connection
availabl
e
< conn.clearInUse();
< synchronized (availableListOfSharedConnections)
< {
< availableListOfSharedConnections.add(sharedConns);
< }
< throw e;
< }
< }
<
199c166
< if(needToBind)
---
> if(needToBind || !conn.isConnectionAlive())

@novell.com Susan Perrin

unread,
Jan 10, 2006, 12:05:41 PM1/10/06
to
Hi

LDAPConnection.clone creates a new LDAPConnection that shares the underlying
tcp/ip socket connection and bind state with the original. It has separate
context for settings such as constraints. I think you should get a choice
whether the pool will create cloned ldap connections or new ldap
connections.

Thank you for the code suggestions, I will forward them to the engineers via
the bug I wrote. However, I don't understand if it addresses the hang
issue. When I ran your original code against eDirectory, it was hanging
when the conneciton timed out from the server. In your fix, you're not
hanging on isConnectionAlive?


When Jim posted that he thought this was related to another bug, the issue
there was that, in order to provide support for earlier versions of JDK, the
sockets aren't set with timeout on reads. Because of that, the only way to
timeout a connection is with a separate thread. The bug Jim mentioned was
to allow a constructor on LDAPConnection that sets timeout on the underlying
socket.

Thank you
Susan

shuhchang

unread,
Jan 10, 2006, 5:24:33 PM1/10/06
to
Susan Perrin wrote:

> Hi

> LDAPConnection.clone creates a new LDAPConnection that shares the underlying
> tcp/ip socket connection and bind state with the original. It has separate
> context for settings such as constraints. I think you should get a choice
> whether the pool will create cloned ldap connections or new ldap
> connections.

Actually, I am not sure how you can pick and choose how LDAPConnection
object got to be created. I thought PoolManager always creates one (the
first one) new LDAPConenction object and then clone the rest with the
first real LDAPConnection object where the constraints also got copied to
the cloned ones.

> Thank you for the code suggestions, I will forward them to the engineers via
> the bug I wrote. However, I don't understand if it addresses the hang
> issue. When I ran your original code against eDirectory, it was hanging
> when the conneciton timed out from the server. In your fix, you're not
> hanging on isConnectionAlive?

When I ran my attempted fix, it seemed to result in a different error.
However, I am not sure whether it's the fix or the way I built the
ldap.jar file. I am having a bit trouble getting the ldap.jar build
properly. Actually, where is the proper link to download the jBroker Web?
I have a hard time to find the proper link for the download. (Is it no
longer a free download? or is it only availble as a 30-day eval version?)

> When Jim posted that he thought this was related to another bug, the issue
> there was that, in order to provide support for earlier versions of JDK, the
> sockets aren't set with timeout on reads. Because of that, the only way to
> timeout a connection is with a separate thread. The bug Jim mentioned was
> to allow a constructor on LDAPConnection that sets timeout on the underlying
> socket.

Aaahhh... I see. This explains another myth that I had with this mslimit
timeout (I assume that is the timeout you were referring to). During my
development with JLDAP, when I set the mslimit timeout in the
LDAPConnection obtained from PoolManager, it doesn't seems to *always* has
the timeout effect reported by the Message objects. When the
LDAPConnection objects are first created/cloned by the PoolManager, the
mslimit values for all the LDAPConnection obejcts are already set to the
default of 0. By the time I get the LDAPConnection object from
PoolManager, it was bound with some Message object reporting an mslimit of
zero. My setting of mslimit would come in later (after the bind operation
done internally by PoolManager). Therefore, no matter how I set the
LDAPConnection object ( obtained from PoolManager), I would always see a
mix of non-zero and zero values of mslimit reported by Message objects --
(my stress tests are multi-threaded.) Thanks for the info.

Shuh


@novell.com Susan Perrin

unread,
Jan 10, 2006, 6:54:37 PM1/10/06
to
> Actually, I am not sure how you can pick and choose how LDAPConnection
> object got to be created

You can't. My thinking was to add a second constructor with an additional
boolean that does something like this:

// Clone the connections to make all of the sharedConns.
for (int j = 1; j < maxSharedConns; j++)
{

Connection newConn = new Connection;
sharedConns.add(newConn);
}

instead of this:


// Clone the connections to make all of the sharedConns.
for (int j = 1; j < maxSharedConns; j++)
{
Connection cloneConn = (Connection)conn.clone();
sharedConns.add(cloneConn);
}

but it was just a thought.

but about the hanging... You don't yet know if you're still hanging, right?

I'll ask about jbroker downloads and post back.


ShuhChang

unread,
Jan 10, 2006, 7:41:00 PM1/10/06
to

"Susan Perrin" <devsup @novell.com> wrote

> You can't. My thinking was to add a second constructor with an additional
> boolean that does something like this:
>
> // Clone the connections to make all of the sharedConns.
> for (int j = 1; j < maxSharedConns; j++)
> {
> Connection newConn = new Connection;
> sharedConns.add(newConn);
> }
>
> but it was just a thought.

Ah, I see.

>
> but about the hanging... You don't yet know if you're still hanging,
> right?
>
> I'll ask about jbroker downloads and post back.
>

That's right.

Shuh


@novell.com Susan Perrin

unread,
Jan 11, 2006, 1:15:32 PM1/11/06
to
I've learned that JBroker is not available by itself anymore; it is actually
bundled with the exteNd suite. In the days of Silverstream, JBroker used to
be an independent web application server, which we endorsed in the NDK, but
now all we have is the exteNd suite, which is available for evaluation
download.


ShuhChang

unread,
Jan 12, 2006, 3:23:19 PM1/12/06
to
"Susan Perrin" <devsup @novell.com> wrote

This confirms what I learned from my adventure on the jBroker search.

I was wondering when I can have a (maybe) pre-next-release of the JLDAP
binary so that I could test out your final fixes on PoolManager. Thanks.

Regards,
Shuh


Jim Willeke

unread,
Jan 13, 2006, 4:32:00 PM1/13/06
to
I think there is a big problem using "cloned" connections in a pool.

From
http://developer.novell.com/ndk/doc/jldap/jldapenu/api/com/novell/ldap/LDAPConnection.html#clone()
"Reauthenticating in a clone, however, is a global operation which will
affect the source object and all associated clones, because it applies
to the single shared physical connection. Any request by an associated
object after one has reauthenticated will carry the new identity."

So does this not imply that if you clone a connection, and then, bind as
a different user, all other connections " will carry the new identity."

So unless you are not binding on a cloned connection object, seems like
the way the poolmanager is created is not useful.

Further, if you issue a StartTLS, it will affect all connections in the
pool.

I wrote (ok, I grabbed a bunch of ideas from others) and put together a
pool manager sometime back for a specific project need.

I attached it for anyone to look over and use or steal ideas from.
Use at own risk.
-jim

LDAPConnectionPool.java

ShuhChang

unread,
Jan 13, 2006, 5:42:30 PM1/13/06
to
"Jim Willeke" <j...@DOT.willeke.com> wrote
\>I think there is a big problem using "cloned" connections in a pool.

Thanks for your input, Jim. I was just about to start writing my own
simplified PoolConnectionManager while waiting for the Novell's PoolManager
code to be fixed.

I totally agree with your assessment of the risk of using cloned
connections. That's why I was trying to use (Nx1) connections, i.e. N
physical connections with only one LDAPConnection each just to avoid using
the cloned ones. I assume the whole idea of designing the cloned connections
was for the efficiency if the credentials of the cloned ones are the same as
the first LDAPConnection on that same physical connection. However, with the
disconnections problem by the LDAP server, it also comes with the penalty.

I have been contemplating several workarounds with the PoolManager
(including using isConnectionAlive() method in LDAPConnection as a keep
alive means for a watchdog, etc.), but none seems to be a good option.

I'll take a closer at your submitted code. Thanks.

Regards,
Shuh


0 new messages