Sun Java logo     Previous      Contents      Index      Next     

Sun logo
Sun Java(TM) System Directory Server 5.2 2005Q1 Plug-In Developer's Guide 

Chapter 7
Performing Internal Operations

This chapter covers how to perform search, add, modify, modify DN, and delete operations for which no corresponding client requests exist.

Finding the Example

The plug-in code used in this chapter can be found in ServerRoot/plugins/slapd/slapi/examples/internal.c.

Before Using the Example

Before using the example plug-in internal.c create a new suffix, dc=example,dc=com, then load the entries from the LDIF example file ServerRoot/slapd-serverID/ldif/Example-Plugin.ldif into the directory. Refer to Setting Up an Example Suffix for instructions.

Refer to the Directory Server Plug-in Developer's Reference for complete reference information concerning the plug-in API functions used in this chapter.

This chapter includes the following sections:


Using Internal Operations

This section demonstrates use of internal search, add, modify, modify RDN, and delete operations.

When to Use Internal Operations

Internal operations are internal in the sense that they are initiated not by external requests from clients, but instead internally by plug-ins. Use internal operation calls when your plug-in needs Directory Server to perform an operation for which no client request exists.

Caveats

You set up the parameter blocks and handle all memory management directly when developing with internal operations. Debugging against optimized binaries such as those delivered with the product can be tedious. Review the code carefully. You may want to work with a partner who can point out errors you miss. Memory management mistakes around internal operation calls lead more quickly to inscrutable segmentation faults than other calls in the plug-in API.

Furthermore, internal operations result in updates to some internal caches but not others. For example, changes to access control instructions cause updates to the access control cache. Internal operation changes to attributes used in CoS and roles do not cause CoS and roles caches to be updated.

The rest of this chapter concerns individual internal operations.


Internal Add

For an internal add, you allocate space for a parameter block, set it up for the add with slapi_add_entry_internal_set_pb() so that the entry is in the parameter block, invoke slapi_add_internal_pb(), and free the parameter block. The internal add consumes the entry passed in to the server through the parameter block.

Code Example 7-1 demonstrates the process for an internal add.

Code Example 7-1 Internal Add Operation (internal.c

#include "slapi-plugin.h"

/* Internal operations require an ID for the plug-in.                   */

static Slapi_ComponentId * plugin_id     = NULL;

int

test_internal()

{

    Slapi_DN       * sdn;              /* DN holder for internal ops    */

    Slapi_Entry    * entry;            /* Entry holder for internal ops */

    Slapi_PBlock   * pb;               /* PBlock for internal ops       */

    char           * str = NULL;       /* String holder for internal ops*/

    int              len;              /* Length of LDIF from entry     */

    int              rc;               /* Return code; 0 means success. */

    /* Check that the example suffix exists.                            */

    sdn = slapi_sdn_new_dn_byval("dc=example,dc=com");

    if (slapi_be_exist(sdn)) {

        slapi_log_info_ex(

            SLAPI_LOG_INFO_AREA_PLUGIN,

            SLAPI_LOG_INFO_LEVEL_DEFAULT,

            SLAPI_LOG_NO_MSGID,

            SLAPI_LOG_NO_CONNID,

            SLAPI_LOG_NO_OPID,

            "test_internal in test-internal plug-in",

            "Suffix (%s) does not exist, exiting.\n",

            slapi_sdn_get_dn(sdn)

        );

        slapi_sdn_free(&sdn);

        return (0);

    }

    slapi_sdn_free(&sdn);

    /*

     * Add an entry for Quentin Cubbins to the example suffix

     * using slapi_add_entry_internal().                                */

    entry = slapi_entry_alloc();

    slapi_entry_set_dn(                /* slapi_entry_set_dn()          */

        entry,                         /* requires a copy of the DN.    */

        slapi_ch_strdup("uid=qcubbins,ou=People,dc=example,dc=com")

    );

                                       /* slapi_entry_add_string()      */

                                       /* does not require a copy.      */

    slapi_entry_add_string(entry, "objectclass", "top");

    slapi_entry_add_string(entry, "objectclass", "person");

    slapi_entry_add_string(entry, "objectclass", "organizationalPerson");

    slapi_entry_add_string(entry, "objectclass", "inetOrgPerson");

    slapi_entry_add_string(entry, "uid", "qcubbins");

    slapi_entry_add_string(entry, "givenName", "Quentin");

    slapi_entry_add_string(entry, "sn", "Cubbins");

    slapi_entry_add_string(entry, "cn", "Quentin Cubbins");

    slapi_entry_add_string(entry, "mail", "qcubbins@example.com");

    slapi_entry_add_string(entry, "userPassword", "qcubbins");

    slapi_entry_add_string(entry, "secretary",

        "uid=bcubbins,ou=People,dc=example,dc=com");

    pb = slapi_pblock_new();           /* Make our own PBlock...        */

    rc = slapi_add_entry_internal_set_pb(

        pb,

        entry,

        NULL,                          /* No controls                   */

        plugin_id,

        SLAPI_OP_FLAG_NEVER_CHAIN      /* Never chain this operation.   */

    );

    if (rc != 0) {

        slapi_pblock_destroy(pb);

        return (-1);            

    }

    str = slapi_entry2str(entry, &len);/* Entry as LDIF for the log.

                                        * Note we have to capture this

                                        * before the internal add, during

                                        * which the entry is consumed.  */

    rc = slapi_add_internal_pb(pb);    /* Entry consumed here           */

                                       /* ... get status ...            */

    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);  

        return (-1);            

    }

    slapi_pblock_destroy(pb);   

    slapi_log_info_ex(

        SLAPI_LOG_INFO_AREA_PLUGIN,

        SLAPI_LOG_INFO_LEVEL_DEFAULT,

        SLAPI_LOG_NO_MSGID,

        SLAPI_LOG_NO_CONNID,

        SLAPI_LOG_NO_OPID,

        "test_internal in test-internal plug-in",

        "\nAdded entry:\n%sEntry length: %d\n", str, len

    );

    return (0);

}

Notice the internal operation requires a plugin_id. As shown, the plug-in ID is a global variable. It is set during plug-in initialization, using

slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_id);

on the parameter block, pb, passed to the plug-in initialization function. Refer to the internal_init() function in internal.c for a sample implementation.


Internal Modify

For internal modify, you first set up an array of LDAPMod modifications containing information about the attribute types you want to modify, and containing the attribute values. Then, similar to internal add, you allocate space for a parameter block, set it up using slapi_modify_internal_set_pb(), invoke the modify operation using slapi_modify_internal_pb(), and finally free the memory used. Code Example 7-2 demonstrates internal modification of a user mail address.

Code Example 7-2 Internal Modify Operation (internal.c

#include "slapi-plugin.h"

static Slapi_ComponentId * plugin_id     = NULL;

int

test_internal()

{

    Slapi_Entry    * entry;            /* Entry holder for internal ops */

    Slapi_PBlock   * pb;               /* PBlock for internal ops       */

    LDAPMod          mod_attr;         /* Attribute to modify           */

    LDAPMod        * mods[2];          /* Array of modifications        */

    char           * mail_vals[]  =    /* New mail address              */

                       {"quentin@example.com", NULL};

    int              rc;               /* Return code; 0 means success. */

    /* Modify Quentin's entry after his email address changes from

     * qcubbins@example.com to quentin@example.com.                     */

    mod_attr.mod_type   = "mail";

    mod_attr.mod_op     = LDAP_MOD_REPLACE;

    mod_attr.mod_values = mail_vals;   /* mail: quentin@example.com     */

    mods[0]             = &mod_attr;

    mods[1]             = NULL;

    pb = slapi_pblock_new();           /* Set up a PBlock...            */

    rc = slapi_modify_internal_set_pb(

        pb,

        "uid=qcubbins,ou=people,dc=example,dc=com",

        mods,

        NULL,                          /* No controls                   */

        NULL,                          /* DN rather than unique ID      */

        plugin_id,

        SLAPI_OP_FLAG_NEVER_CHAIN      /* Never chain this operation.   */

    );

    if (rc != 0) {

        slapi_pblock_destroy(pb);

        return (-1);            

    }

    rc = slapi_modify_internal_pb(pb); /* Unlike internal add,          */

                                       /* nothing consumed here         */

                                       /* ... get status ...            */

    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);          

        return (-1);            

    }

    

    slapi_pblock_destroy(pb);          /* ... clean up the PBlock.      */

    slapi_log_info_ex(

        SLAPI_LOG_INFO_AREA_PLUGIN,

        SLAPI_LOG_INFO_LEVEL_DEFAULT,

        SLAPI_LOG_NO_MSGID,

        SLAPI_LOG_NO_CONNID,

        SLAPI_LOG_NO_OPID,

        "test_internal in test-internal plug-in",

        "\nModified attribute: %s\nNew value: %s\n",

        mod_attr.mod_type, mail_vals[0]

    );

    return (0);

}

Notice the data in mod_attr and mail_vals is still available for use after the modification. Unlike internal add, internal modify does not consume the data you set in the parameter block.


Internal Rename and Move (Modify DN)

This section describes how to develop a plug-in to rename an entry, or to move an entry.

An internal modify DN operation is performed in the following stages:

  1. Allocate space for a parameter block.
  2. Set up the operation by using slapi_rename_internal_set_pb().
  3. Invoke the operation by using slapi_modrdn_internal_pb() — notice that the first stage of the operation is rename, and the second stage of the operation is modrdn.
  4. Free the parameter block.

Code Example 7-3 demonstrates an internal modify DN.

Code Example 7-3 Internal Rename or Move Operation (internal.c

#include "slapi-plugin.h"

static Slapi_ComponentId * plugin_id     = NULL;

int

test_internal()

{

    Slapi_PBlock   * pb;               /* PBlock for internal ops       */

    int              rc;               /* Return code; 0 means success. */

    pb = slapi_pblock_new();           /* Set up a PBlock again...      */

    rc = slapi_rename_internal_set_pb(

        pb,

        "uid=qcubbins,ou=people,dc=example,dc=com", /* Specify target entry */

        "uid=fcubbins",                             /* Specify new RDN      */

        "ou=people,dc=example,dc=com",              /* Specify new superior */

        /* The new superior is the same as the old superior. This operation is a rename */

        1,                             /* Delete old RDN                */

        NULL,                          /* No controls                   */

        NULL,                          /* DN rather than unique ID      */

        plugin_id,

        SLAPI_OP_FLAG_NEVER_CHAIN      /* Never chain this operation.   */

    );

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);          

        return (-1);            

    }

    rc = slapi_modrdn_internal_pb(pb); /* Like internal modify,         */

                                       /* nothing consumed here.        */

                                       /* ... get status ...            */

    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);          

        return (-1);

    }

    slapi_pblock_destroy(pb);          /* ... cleaning up.              */

    slapi_log_info_ex(

        SLAPI_LOG_INFO_AREA_PLUGIN,

        SLAPI_LOG_INFO_LEVEL_DEFAULT,

        SLAPI_LOG_NO_MSGID,

        SLAPI_LOG_NO_CONNID,

        SLAPI_LOG_NO_OPID,

        "test_internal in test-internal plug-in",

        "\nNew entry RDN: %s\n", "uid=fcubbins"

    );

    return (0);

}

Internal modify DN does not consume the data you set in the parameter block.


Internal Search

For an internal search, use callbacks to retrieve what the server finds. The callbacks let you retrieve what would be sent back to a client application were the operation initiated by an external request: LDAP result codes, entries found, and referrals.

You set up the callback data you want to retrieve, and write the function called back by the server. Code Example 7-4 shows how the example plug-in internal.c uses a callback to retrieve an LDIF representation of the first entry found during an internal search using slapi_entry2str() in the callback function.

Code Example 7-4 Search Callback (internal.c

#include "slapi-plugin.h"

struct cb_data {                       /* Data returned from search     */

    char * e_str;                      /* Entry as LDIF                 */

    int    e_len;                      /* Length of LDIF                */

};

int

test_internal_entry_callback(Slapi_Entry * entry, void * callback_data)

{

    struct cb_data * data;

    int              len;

    /* This callback could do something more interesting with the

     * data such as build an array of entries returned by the search.

     * Here we simply log the result.                                   */

    data        = (struct cb_data *)callback_data;

    data->e_str = slapi_entry2str(entry, &len);

    data->e_len = len;

    slapi_log_info_ex(

        SLAPI_LOG_INFO_AREA_PLUGIN,

        SLAPI_LOG_INFO_LEVEL_DEFAULT,

        SLAPI_LOG_NO_MSGID,

        SLAPI_LOG_NO_CONNID,

        SLAPI_LOG_NO_OPID,

        "test_internal_entry_callback in test-internal plug-in",

        "\nFound entry: %sLength: %d\n", data->e_str, data->e_len

    );

    return (-1);                       /* Stop at the first entry.      */

}                                      /* To continue, return 0.        */

The callback here stops the search at the first entry. Your plug-in may have to deal with more than one entry being returned by the search, so consider how you want to allocate space for your data depending on what your plug-in does.

With the callback data and function implemented, you are ready to process the internal search. First, allocate space for the parameter block and your callback data, and set up the parameter block using slapi_search_internal_pb_set(). Next, invoke the search using slapi_search_internal_pb(), and also set up the callback using slapi_search_internal_callback_pb(). Finally, free the space allocated when you are finished.

Code Example 7-5 demonstrates an internal search.

Code Example 7-5 Internal Search Operation (internal.c

#include "slapi-plugin.h"

static Slapi_ComponentId * plugin_id     = NULL;

int

test_internal()

{

    Slapi_PBlock   * pb;               /* PBlock for internal ops       */

    char           * srch_attrs[] =    /* Attr. to get during search    */

                       {LDAP_ALL_USER_ATTRS, NULL};

    struct cb_data   callback_data;    /* Data returned from search     */

    int              rc;               /* Return code; 0 means success. */

    slapi_log_info_ex(

        SLAPI_LOG_INFO_AREA_PLUGIN,

        SLAPI_LOG_INFO_LEVEL_DEFAULT,

        SLAPI_LOG_NO_MSGID,

        SLAPI_LOG_NO_CONNID,

        SLAPI_LOG_NO_OPID,

        "test_internal in test-internal plug-in",

        "\nSearching with base DN %s, filter %s...\n",

        "dc=example,dc=com", "(uid=fcubbins)"

    );

    pb = slapi_pblock_new();           /* Set up a PBlock...            */

    rc = slapi_search_internal_set_pb(

        pb,

        "dc=example,dc=com",           /* Base DN for search            */

        LDAP_SCOPE_SUBTREE,            /* Scope                         */

        "(uid=fcubbins)",              /* Filter                        */

        srch_attrs,                    /* Set to get all user attrs.    */

        0,                             /* Return attrs. and values      */

        NULL,                          /* No controls                   */

        NULL,                          /* DN rather than unique ID      */

        plugin_id,

        SLAPI_OP_FLAG_NEVER_CHAIN      /* Never chain this operation.   */

    );

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);          

        return (-1);            

    }

    /* Internal search puts results into the PBlock, but we use callbacks

     * to get at the data as it is turned up by the search. In this case,

     * what we want to get is the entry found by the search.            */

    rc  = slapi_search_internal_pb(pb);

    rc |= slapi_search_internal_callback_pb(

        pb,

        &callback_data,

        NULL,                          /* No result callback            */

        test_internal_entry_callback,

        NULL                           /* No referral callback          */

    );

                                       /* ... get status ...            */

    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);          

        return -1;

    }

                                       /* Free the search results when

                                        * finished with them.           */

    slapi_free_search_results_internal(pb);

    slapi_pblock_destroy(pb);          /* ... done cleaning up.         */

    return (0);

}

Here we allocate and free callback_data locally. You may want to manage memory differently if you pass the data to another plug-in function.


Internal Delete

For internal delete, you allocate space for the parameter block, set it up using slapi_delete_internal_set_pb(), invoke the delete using slapi_delete_internal_pb(), and finally free the parameter block. Code Example 7-6 demonstrates an internal delete.

Code Example 7-6 Internal Delete Operation (internal.c

#include "slapi-plugin.h"

static Slapi_ComponentId * plugin_id     = NULL;

int

test_internal()

{

    Slapi_PBlock   * pb;               /* PBlock for internal ops       */

    int              rc;               /* Return code; 0 means success. */

    pb = slapi_pblock_new();           /* Set up a PBlock...            */

    rc = slapi_delete_internal_set_pb(

        pb,

        "uid=fcubbins,ou=people,dc=example,dc=com",

        NULL,                          /* No controls                   */

        NULL,                          /* DN rather than unique ID      */

        plugin_id,

        SLAPI_OP_FLAG_NEVER_CHAIN      /* Never chain this operation.   */

    );

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);          

        return -1;

    }

    rc = slapi_delete_internal_pb(pb); /* Does not consume any          */

                                       /* data set in the PBlock.       */

                                       /* ... get status ...            */

    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);

    if (rc != LDAP_SUCCESS) {

        slapi_pblock_destroy(pb);          

        return -1;

    }

    slapi_pblock_destroy(pb);          /* ... cleaning up.              */

    slapi_log_info_ex(

        SLAPI_LOG_INFO_AREA_PLUGIN,

        SLAPI_LOG_INFO_LEVEL_DEFAULT,

        SLAPI_LOG_NO_MSGID,

        SLAPI_LOG_NO_CONNID,

        SLAPI_LOG_NO_OPID,

        "test_internal in test-internal plug-in",

        "\nDeleted entry with DN: %s\n",

        "uid=fcubbins,ou=people,dc=example,dc=com"

    );

    return (0);

}

As mentioned in the excerpt, internal delete does not consume the data you set in the parameter block.



Previous      Contents      Index      Next     


Copyright 2005 Sun Microsystems, Inc. All rights reserved.