UnboundID Server SDK

Ping Identity
UnboundID Server SDK Documentation

ExampleVirtualAttributeProvider.java

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * docs/licenses/cddl.txt
 * or http://www.opensource.org/licenses/cddl1.php.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * docs/licenses/cddl.txt.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2010-2023 Ping Identity Corporation
 */
package com.unboundid.directory.sdk.examples;



import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import com.unboundid.directory.sdk.common.types.Entry;
import com.unboundid.directory.sdk.common.types.OperationContext;
import com.unboundid.directory.sdk.ds.api.VirtualAttributeProvider;
import com.unboundid.directory.sdk.ds.config.VirtualAttributeProviderConfig;
import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.StringArgument;



/**
 * This class provides a simple example of a virtual attribute provider that
 * will generate a virtual attribute whose value will be the reverse of another
 * attribute in the same entry.  It takes a single configuration argument:
 * <UL>
 *   <LI>source-attribute -- The name of the attribute in the entry whose value
 *       will be reversed to obtain the values for the virtual attribute.</LI>
 * </UL>
 */
public final class ExampleVirtualAttributeProvider
       extends VirtualAttributeProvider
{
  /**
   * The name of the argument that will be used for the argument used to specify
   * the attribute whose values should be reversed.
   */
  private static final String ARG_NAME_ATTR = "source-attribute";



  // The server context for the server in which this extension is running.
  private DirectoryServerContext serverContext;

  // The source attribute from which to obtain the data for the virtual
  // attribute.
  private volatile String sourceAttribute;



  /**
   * Creates a new instance of this virtual attribute provider.  All virtual
   * attribute provider implementations must include a default constructor, but
   * any initialization should generally be done in the
   * {@code initializeVirtualAttributeProvider} method.
   */
  public ExampleVirtualAttributeProvider()
  {
    // No implementation required.
  }



  /**
   * Retrieves a human-readable name for this extension.
   *
   * @return  A human-readable name for this extension.
   */
  @Override()
  public String getExtensionName()
  {
    return "Example Virtual Attribute Provider";
  }



  /**
   * Retrieves a human-readable description for this extension.  Each element
   * of the array that is returned will be considered a separate paragraph in
   * generated documentation.
   *
   * @return  A human-readable description for this extension, or {@code null}
   *          or an empty array if no description should be available.
   */
  @Override()
  public String[] getExtensionDescription()
  {
    return new String[]
    {
      "This virtual attribute provider serves as an example that may be used " +
           "to demonstrate the process for creating a third-party virtual " +
           "attribute provider.  It will generate an attribute whose values " +
           "are the same as the values of another attribute in the same " +
           "entry but with the characters of those values in reverse order."
    };
  }



  /**
   * Updates the provided argument parser to define any configuration arguments
   * which may be used by this virtual attribute provider.  The argument parser
   * may also be updated to define relationships between arguments (e.g., to
   * specify required, exclusive, or dependent argument sets).
   *
   * @param  parser  The argument parser to be updated with the configuration
   *                 arguments which may be used by this virtual attribute
   *                 provider.
   *
   * @throws  ArgumentException  If a problem is encountered while updating the
   *                             provided argument parser.
   */
  @Override()
  public void defineConfigArguments(final ArgumentParser parser)
         throws ArgumentException
  {
    // Add an argument that allows you to specify the source attribute name.
    Character shortIdentifier = null;
    String    longIdentifier  = ARG_NAME_ATTR;
    boolean   required        = true;
    int       maxOccurrences  = 1;
    String    placeholder     = "{attr}";
    String    description     = "The name of the attribute whose values " +
         "should be reversed to generate the values for the virtual attribute.";

    parser.addArgument(new StringArgument(shortIdentifier, longIdentifier,
         required, maxOccurrences, placeholder, description));
  }



  /**
   * Initializes this virtual attribute provider.
   *
   * @param  serverContext  A handle to the server context for the server in
   *                        which this extension is running.
   * @param  config         The general configuration for this virtual attribute
   *                        provider.
   * @param  parser         The argument parser which has been initialized from
   *                        the configuration for this virtual attribute
   *                        provider.
   *
   * @throws  LDAPException  If a problem occurs while initializing this virtual
   *                         attribute provider.
   */
  @Override()
  public void initializeVirtualAttributeProvider(
                   final DirectoryServerContext serverContext,
                   final VirtualAttributeProviderConfig config,
                   final ArgumentParser parser)
         throws LDAPException
  {
    this.serverContext = serverContext;

    // Get the source attribute name.
    final StringArgument arg =
         (StringArgument) parser.getNamedArgument(ARG_NAME_ATTR);
    sourceAttribute = arg.getValue();
  }



  /**
   * Indicates whether the configuration contained in the provided argument
   * parser represents a valid configuration for this extension.
   *
   * @param  config               The general configuration for this virtual
   *                              attribute provider.
   * @param  parser               The argument parser which has been initialized
   *                              with the proposed configuration.
   * @param  unacceptableReasons  A list that can be updated with reasons that
   *                              the proposed configuration is not acceptable.
   *
   * @return  {@code true} if the proposed configuration is acceptable, or
   *          {@code false} if not.
   */
  @Override()
  public boolean isConfigurationAcceptable(
                      final VirtualAttributeProviderConfig config,
                      final ArgumentParser parser,
                      final List<String> unacceptableReasons)
  {
    // The argument parser will handle all of the necessary validation, so
    // we don't need to do anything here.
    return true;
  }



  /**
   * Attempts to apply the configuration contained in the provided argument
   * parser.
   *
   * @param  config                The general configuration for this virtual
   *                               attribute provider.
   * @param  parser                The argument parser which has been
   *                               initialized with the new configuration.
   * @param  adminActionsRequired  A list that can be updated with information
   *                               about any administrative actions that may be
   *                               required before one or more of the
   *                               configuration changes will be applied.
   * @param  messages              A list that can be updated with information
   *                               about the result of applying the new
   *                               configuration.
   *
   * @return  A result code that provides information about the result of
   *          attempting to apply the configuration change.
   */
  @Override()
  public ResultCode applyConfiguration(
                         final VirtualAttributeProviderConfig config,
                         final ArgumentParser parser,
                         final List<String> adminActionsRequired,
                         final List<String> messages)
  {
    // Get the new source attribute name.
    final StringArgument arg =
         (StringArgument) parser.getNamedArgument(ARG_NAME_ATTR);
    sourceAttribute = arg.getValue();

    return ResultCode.SUCCESS;
  }



  /**
   * Performs any cleanup which may be necessary when this virtual attribute
   * provider is to be taken out of service.
   */
  @Override()
  public void finalizeVirtualAttributeProvider()
  {
    // No implementation required.
  }



  /**
   * Indicates whether the server may cache values generated by this virtual
   * attribute provider for reuse against the same entry in the course of
   * processing the same operation.
   *
   * @return  {@code true} if the server may cache the value generated by this
   *          virtual attribute provider for reuse with the same entry in the
   *          same operation, or {@code false} if not.
   */
  @Override()
  public boolean mayCacheInOperation()
  {
    // The values of this virtual attribute are safe to cache.
    return true;
  }



  /**
   * Indicates whether this virtual attribute provider may generate attributes
   * with multiple values.
   *
   * @return  {@code true} if this virtual attribute provider may generate
   *          attributes with multiple values, or {@code false} if it will only
   *          generate single-valued attributes.
   */
  @Override()
  public boolean isMultiValued()
  {
    // If the source attribute is multi-valued, then the virtual attribute will
    // also be multi-valued.
    return true;
  }



  /**
   * Generates an attribute for inclusion in the provided entry.
   *
   * @param  operationContext  The operation context for the operation in
   *                           progress, if any.  It may be {@code null} if no
   *                           operation is available.
   * @param  entry             The entry for which the attribute is to be
   *                           generated.
   * @param  attributeName     The name of the attribute to be generated.
   *
   * @return  The generated attribute, or {@code null} if no attribute should be
   *          generated.
   */
  @Override()
  public Attribute generateAttribute(final OperationContext operationContext,
                                     final Entry entry,
                                     final String attributeName)
  {
    final List<Attribute> attrList = entry.getAttribute(sourceAttribute);
    if ((attrList == null) || attrList.isEmpty())
    {
      // The source attribute doesn't exist, so we can't generate a virtual
      // attribute.
      if (serverContext.debugEnabled())
      {
        serverContext.debugInfo("Returning null because attribute " +
             sourceAttribute + " does not exist in entry " + entry.getDN());
      }
      return null;
    }

    final LinkedHashSet<String> values = new LinkedHashSet<String>();
    for (final Attribute a : attrList)
    {
      for (final String s : a.getValues())
      {
        values.add(new StringBuilder(s).reverse().toString());
      }
    }

    if (values.isEmpty())
    {
      if (serverContext.debugEnabled())
      {
        serverContext.debugInfo("Returning null because attribute " +
             sourceAttribute + " does not have any values in entry " +
             entry.getDN());
      }
      return null;
    }
    else
    {
      final Attribute va = new Attribute(attributeName, values);
      if (serverContext.debugEnabled())
      {
        serverContext.debugInfo("Generated virtual attribute " + va);
      }

      return va;
    }
  }



  /**
   * Retrieves a map containing examples of configurations that may be used for
   * this extension.  The map key should be a list of sample arguments, and the
   * corresponding value should be a description of the behavior that will be
   * exhibited by the extension when used with that configuration.
   *
   * @return  A map containing examples of configurations that may be used for
   *          this extension.  It may be {@code null} or empty if there should
   *          not be any example argument sets.
   */
  @Override()
  public Map<List<String>,String> getExamplesArgumentSets()
  {
    final LinkedHashMap<List<String>,String> exampleMap =
         new LinkedHashMap<List<String>,String>(1);

    exampleMap.put(
         Arrays.asList(ARG_NAME_ATTR + "=cn"),
         "Generate a virtual attribute whose values will be the reverse of " +
              "the values of the cn attribute in the same entry.");

    return exampleMap;
  }
}