UnboundID LDAP SDK for Java

Ping Identity
Product Information
Using the LDAP SDK Persistence Framework

An Example Demonstrating the Use of the LDAP SDK Persistence Framework

Assume that we wish to interact with a very simple object that may contain one string value and multiple numeric values. The LDAP schema that might be used to represent such an entry might look something like the following:

attributeTypes: ( 1.3.6.1.4.1.32473.1.1
  NAME 'myStringAttr'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.4.1.32473.1.2
  NAME 'myNumericAttr'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
objectClasses: ( 1.3.6.1.4.1.32473.2.1
  NAME 'myStructuralClass'
  SUP top
  STRUCTURAL
  MUST  myStringAttr
  MAY myNumericAttr )

If this schema is already defined in an LDAP directory server, then you can use the generate-source-from-schema tool to generate Java source code for a class that can be used to interact with objects of this type. The command that could be used to generate this source file would look something like:

tools/generate-source-from-schema \
     --hostname directory.example.com \
     --port 389 \
     --bindDN "uid=admin,dc=example,dc=com" \
     --bindPassword "password" \
     --outputDirectory /sandbox/demo/src/com/example \
     --structuralClass myStructuralClass \
     --rdnAttribute myStringAttr \
     --defaultParentDN "dc=example,dc=com" \
     --packageName com.example \
     --className MyObject

The Java source file generated from this command will look like the following:

package com.example;



import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.ReadOnlyEntry;
import com.unboundid.ldap.sdk.persist.FilterUsage;
import com.unboundid.ldap.sdk.persist.LDAPEntryField;
import com.unboundid.ldap.sdk.persist.LDAPField;
import com.unboundid.ldap.sdk.persist.LDAPObject;
import com.unboundid.ldap.sdk.persist.LDAPPersistException;



/**
 * This class was generated by the generate-source-from-schema tool
 * provided with the UnboundID LDAP SDK for Java.  It may be customized as
 * desired to better suit your needs.
 */
@LDAPObject(structuralClass="myStructuralClass",
            defaultParentDN="dc=example,dc=com",
            postDecodeMethod="doPostDecode",
            postEncodeMethod="doPostEncode")
public class MyObject
{
  // The field to use to hold a read-only copy of the associated entry.
  @LDAPEntryField()
  private ReadOnlyEntry ldapEntry;

  // The field used for RDN attribute myStringAttr.
  @LDAPField(attribute="myStringAttr",
             objectClass="myStructuralClass",
             inRDN=true,
             filterUsage=FilterUsage.ALWAYS_ALLOWED,
             requiredForEncode=true)
  private String myStringAttr;

  // The field used for optional attribute myNumericAttr.
  @LDAPField(attribute="myNumericAttr",
             objectClass="myStructuralClass",
             filterUsage=FilterUsage.CONDITIONALLY_ALLOWED)
  private Long[] myNumericAttr;



  /**
   * Creates a new instance of this object.  All fields will be uninitialized,
   * so the setter methods should be used to assign values to them.
   */
  public MyObject()
  {
    // No initialization will be performed by default.  Note that if you set
    // values for any fields marked with an @LDAPField, @LDAPDNField, or
    // @LDAPEntryField annotation, they will be overwritten in the course of
    // decoding initializing this object from an LDAP entry.
  }



  /**
   * Performs any processing that may be necessary after initializing this
   * object from an LDAP entry.
   *
   * @throws  LDAPPersistException  If the generated entry should not be used.
   */
  private void doPostDecode()
          throws LDAPPersistException
  {
    // No processing is needed by default.  You may provide an implementation
    // for this method if custom post-decode processing is needed.
  }



  /**
   * Performs any processing that may be necessary after encoding this object
   * to an LDAP entry.
   *
   * @param  entry  The entry that has been generated.  It may be altered if
   *                desired.
   *
   * @throws  LDAPPersistException  If there is a problem with the object after
   *                                it has been decoded from an LDAP entry.
   */
  private void doPostEncode(final Entry entry)
          throws LDAPPersistException
  {
    // No processing is needed by default.  You may provide an implementation
    // for this method if custom post-encode processing is needed.
  }



  /**
   * Retrieves a read-only copy of the entry with which this object is
   * associated, if it is available.  It will only be available if this object
   * was decoded from or encoded to an LDAP entry.
   *
   * @return  A read-only copy of the entry with which this object is
   *          associated, or {@code null} if it is not available.
   */
  public ReadOnlyEntry getLDAPEntry()
  {
    return ldapEntry;
  }



  /**
   * Retrieves the DN of the entry with which this object is associated, if it
   * is available.  It will only be available if this object was decoded from or
   * encoded to an LDAP entry.
   *
   * @return  The DN of the entry with which this object is associated, or
   *          {@code null} if it is not available.
   */
  public String getLDAPEntryDN()
  {
    if (ldapEntry == null)
    {
      return null;
    }
    else
    {
      return ldapEntry.getDN();
    }
  }



  /**
   * Retrieves the value for the field associated with the
   * myStringAttr attribute, if defined.
   *
   * @return  The value for the field associated with the
   *          myStringAttr attribute, or
   *          {@code null} if it is not defined.
   */
  public String getMyStringAttr()
  {
    return myStringAttr;
  }



  /**
   * Sets the value for the field associated with the
   * myStringAttr attribute.
   *
   * @param  v  The value for the field associated with the
   *            myStringAttr attribute.
   */
  public void setMyStringAttr(final String v)
  {
    this.myStringAttr = v;
  }



  /**
   * Retrieve the first value for the field associated with the
   * myNumericAttr attribute, if defined.
   *
   * @return  The first value for the field associated with the
   *          myNumericAttr attribute, or
   *          {@code null} if it is not defined or does not have any values.
   */
  public Long getFirstMyNumericAttr()
  {
    if ((myNumericAttr == null) ||
        (myNumericAttr.length == 0))
    {
      return null;
    }
    else
    {
      return myNumericAttr[0];
    }
  }



  /**
   * Retrieves the values for the field associated with the
   * myNumericAttr attribute, if defined.
   *
   * @return  The values for the field associated with the
   *          myNumericAttr attribute, or
   *          {@code null} if it is not defined.
   */
  public Long[] getMyNumericAttr()
  {
    return myNumericAttr;
  }



  /**
   * Sets the values for the field associated with the
   * myNumericAttr attribute.
   *
   * @param  v  The values for the field associated with the
   *            myNumericAttr attribute.
   */
  public void setMyNumericAttr(final Long... v)
  {
    this.myNumericAttr = v;
  }
}

At this point, the class can be used in conjunction with the LDAP SDK persistence framework. For example, the following code could be used to interact with objects of this type using the persistence framework:

public void testMyObject(final LDAPConnection connection)
       throws LDAPPersistException
{
  // Create an LDAPPersister instance for MyObject objects.
  LDAPPersister<MyObject> persister =
       LDAPPersister.getInstance(MyObject.class);

  // Create a new MyObject instance and add it to the directory.  We can use
  // a parent DN of null to indicate that it should use the default defined
  // in the @LDAPObject annotation.
  MyObject o = new MyObject();
  o.setMyStringAttr("test");
  o.setMyNumericAttr(1L, 2L, 3L);
  persister.add(o, connection, null);

  // Retrieve the entry from the server and replace the set of numeric values.
  o = persister.get(o, connection, null);
  o.setMyNumericAttr(4L);
  persister.modify(o, connection, null, false);

  // Perform a search to find all instances with a string value of "test",
  // then delete them from the server.
  o = new MyObject();
  o.setMyStringAttr("test");
  PersistedObjects<MyObject> results = persister.search(o, connection);
  while (true)
  {
    o = results.next();
    if (o == null)
    {
      break;
    }

    persister.delete(o, connection);
  }
}

The entry created by the add operation above should look like the following when represented using LDIF:

dn: myStringAttr=test,dc=example,dc=com
objectClass: top
objectClass: myStructuralClass
myStringAttr: test
myNumericAttr: 1
myNumericAttr: 2
myNumericAttr: 3