Question

I have an application that is using Spring LDAP 1.3.1. It is creating the LdapTemplate in a Spring context at startup, passing it in to my application. The LDAP string I am connecting to is in reality a VIP appliance with multiple Active Directory servers behind it.

The application is used to create a group hierarchy, and does so in several steps. First, it creates any new groups, then removes any deleted groups, then updates and changed groups, and finally it updates the parent of any new or moved groups.

In that last step, in order to do the move, I have to look up the group, then look up it's parent, and finally update the Member list of the parent to remove the child.

Here is where the problem starts. Every so often, but not every time, I have a run in which the group is added but when the code tries to set the parent, it fails because the new group isn't there yet. I believe what is happening is that Spring LDAP is reconnecting on each call, and because I am going through a VIP and the AD server is round-robin'ed, I think the newly added group hasn't replicated, so selecting the group returns null and my parent update fails. Basically I think I am running into a race condition with AD replication.

So, long explanation short: Does Spring LDAP 1.3.1, and in particular the LdapTemplate, create a new connection each time, or am I misunderstanding how it works? Is there a way to make it use a pooled connection, either by configuration of the LdapTemaplate or by setting com.sun.jndi.ldap.connect.pool? If I used only one connection for the entire application run, it should solve the replication (if that is what's occuring) problem in that I would be stuck to one AD server and not bouncing around.

Was it helpful?

Solution

To all future Devs who may stumble across this post, this is how I fixed the issue...

In Spring LDAP 1.3.2, SingleContextSource does not have a constructor that takes a ContextSource, but rather only one that takes a DirContext. I didn't see any means to get a single DirContext from my LdapContextSource, so I was unable to use the suggestion of ig0774.

However, having read the Oracle documentation, I found that it has built-in since 1.4.1 a VERY simple pooling mechanism. Further reading in the Spring API docs for LdapContextSource showed that it has the ability to turn this pooling mechanism on through a call to setPooled(boolean). This basically makes it so that the call to close() on the connections doesn't not really close the connection, but rather returns it to the "pool". Since my application is one big linear thread, and only one "connection" is opened at a given time, this has the net effect of causing it to simply use the same connection, thus bypassing the issue I was seeing were my updates were working faster than the replication. After turning on the built-in pooling, my errors have seemingly stopped.

Note that this is NOT a good means to implement a pooling scheme for LDAP. As the JavaDoc says, this built-in pooling mechanism has many flaws. If you need pooling, then you are MUCH better off using Spring LDAP's PoolingContextSource. In my case, however, I wanted the opposite of a "pool", so things seemed to work out for me in that regard.

The other option would have been to simply not use the VIP but rather connect directly to a single Active Directory server, but then I loose fail-over ability.

OTHER TIPS

You could be right, as LdapTemplate does appear to close the connection after every operation. One way of mitigating your problem would be to switch your Spring configuration so that you are using a SingleContextSource as a wrapper for your current contextSource supplied to your LdapTemplate. Depending on your configuration, this may look something like this:

<beans>
   <bean id="contextSource"
      class="org.springframework.ldap.core.support.LdapContextSource">
      <property name="url" value="ldap://localhost:389" />
      <property name="base" value="dc=fabrikam,dc=com" />
      <property name="userName" value="cn=superuser,dc=fabrikam,dc=com" />
      <property name="password" value="secret" />
   </bean>

   <bean id="contextSourceWrapper"
      class="org.springframework.ldap.core.support.SingleContextSource">
      <constructor-arg ref="contextSource" />
   </bean>

   <bean id="ldapTemplate"
      class="org.springframework.ldap.core.LdapTemplate">
      <constructor-arg ref="contextSourceWrapper" />
   </bean>
</beans>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top