LDAP SDK Features: Developer-Friendly Elements

One of the things that we’ve tried to do with the UnboundID LDAP SDK for Java is to make it as easy as possible to use. Some of this is kind of intangible (e.g., providing convenience methods for doing common things that might take multiple steps in other APIs), but there are things that I think are worth mentioning that we’ve done in this area to help developers write better applications. I’ll describe some of them here.

Extensive Javadoc Documentation

We provide a number of different types of documentation with the LDAP SDK (also available online at http://www.unboundid.com/products/ldapsdk/docs/), but I think that the most helpful documentation is the Javadoc that we generate from the source code. All public and protected methods are documented, including information about each argument and the value returned, and all public and protected fields are also documented.

Other than providing information about the available fields and methods, some of the most useful information included in the Javadoc is the class-level documentation that we provide. In many cases, this is quite extensive, and we include a number of code snippets that demonstrate how to use that class. For example, the class-level documentation for nearly all of the request types as well as the controls and extended operations provide examples for using them.

Another benefit of our Javadoc documentation is that we have generated it with the “-linksource” option, so that means that the entire source code for all of the documented classes is included as part of the documentation. This makes it possible to click on the name of a class or method in the Javadoc and be taken directly to the source code for it. In the event that you have a question about the API that can’t be answered by the Javadoc documentation itself, then using this to look at the source code itself can be very useful.

Annotations

The Javadoc documentation provides extensive information about how to use the LDAP SDK, but by itself there are some questions which a developer might have for which the answers aren’t immediately obvious. For many of these, we have defined annotations that may help make this clearer. Some of those annotations include:

  • @ThreadSafety — In many APIs, there isn’t much documentation available about the behavior of the associated code when accessed concurrently by multiple threads. To help make it clearer for our LDAP SDK, all public classes and interfaces have been marked with the @ThreadSafety annotation that indicates how those types of object may be treated in multithreaded contexts.
  • @Extensible / @NotExtensible — These annotations are used to mark interfaces and non-final classes to indicate whether they are intended to be extended by third-party code. There are some interfaces and non-final classes in the LDAP SDK which are primarily intended to be extended only by code within the LDAP SDK, and they have been marked with the @NotExtensible annotation. On the other hand, a number of interfaces and non-final classes are safe to extend by third-party code, and they are marked with the @Extensible annotation.
  • @Mutable / @NotMutable — These annotations are used to mark classes to indicate whether objects of that type are allowed to be altered by third party code. Most classes which are marked @NotMutable are fully immutable so there is no way to alter their contents at all, but there are a few cases in which it is necessary for an object to be modifiable by code within the LDAP SDK, and in those cases the associated class is marked @NotMutable to indicate that those objects shouldn’t be externally altered. For objects which may be safely altered by third-party code, the classes are marked @Mutable.
  • @InternalUseOnly — There are a few cases within the LDAP SDK where constraints enforced by Java require a class or method to be public but we don’t intend for it to be used by external code (e.g., a method required by an internal interface). In such cases, the associated class or method is marked with the @InternalUseOnly annotation to indicate that it’s not intended to be used by third-party code.

These annotations have a “runtime” retention, so they are accessible via reflection (and in fact, we have a number of unit tests to ensure that classes are marked correctly). They also appear in the generated Javadoc documentation, so that helps further improve the quality of the Javadoc.

Generics

Wherever appropriate, the LDAP SDK makes full use of generics. This is particularly true for all collections that are used anywhere in the code. This is very useful for developers because it helps them understand the types of element contained in that collection.

Debugging Support

If something goes wrong with a program using the LDAP SDK, then it may be helpful to debug the processing performed by the LDAP SDK. You can, of course, step through the code using a Java debugger, but you can also enable debugging support within the LDAP SDK itself. This uses the Java logging framework to provide messages about actions performed within the SDK, including:

  • Establishing and closing connections to directory servers
  • LDAP requests sent and responses received
  • ASN.1 elements encoded and decoded
  • LDIF entries and change records read and written
  • Exceptions caught within the LDAP SDK
  • Information about coding errors in which the LDAP SDK was used incorrectly (e.g., an argument that was inappropriately null or had a value outside of an acceptable range)

These types of debugging can be enabled or disabled on an individual basis, and you can control the minimum log level for messages that you want to see.

Debugging can be enabled or disabled programmatically by code using the LDAP SDK by calling methods in the com.unboundid.util.Debug class). However, debugging can also be controlled through the use of Java properties without the need to make any changes in the code using the LDAP SDK. The following properties are defined for use:

  • com.unboundid.ldap.sdk.debug.enabled — If this property is set to “true“, then debugging will be enabled.
  • com.unboundid.ldap.sdk.debug.level— If this property is set, then it may control the minimum debug level for messages to be written. Allowed debug levels include ALL, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, or OFF.
  • com.unboundid.ldap.sdk.debug.type — This may be set to a comma-delimited list of the types of debugging to be used within the LDAP SDK. Available debug types include ASN1, CODING_ERROR, CONNECT, EXCEPTION, LDAP, LDIF, and OTHER. If this property is not set, then all debug types will be used.

If debugging is enabled, then it will use a logger name of “com.unboundid.ldap.sdk“. By default, messages will be written to standard error, although the Java logging framework can be configured to use a custom logger to send the messages elsewhere.

Disconnect Notification

With many APIs that provide LDAP communication, if a connection to the directory server is lost, then the application may have no way of knowing until it tries to use that connection, and at that point it is often not possible to understand when the connection was closed or for what reason.

The UnboundID LDAP SDK for Java provides a com.unboundid.ldap.sdk.DisconnectHandler interface, which may be implemented by third-party code to provide a mechanism to notify an application whenever it detects that a connection has been closed. This interface defines the following method:

void handleDisconnect(LDAPConnection connection,
String host,
int port,
DisconnectType disconnectType,
String message,
Throwable cause)

Whenever a connection has been closed, the disconnect handler’s handleDisconnect method will be called to notify it of the disconnect and provide information about it. The DisconnectType element will provide information about the reason for the disconnect, and can be used to indicate whether the closure was expected (e.g., by calling connection.close() to perform an LDAP unbind). If desirable, the disconnect handler may attempt to re-establish the connection (perhaps to a different server), which may help avoid user-visible failures that may result from attempting to use the connection.