All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.ldap.sdk.transformations.ReplaceWithCounterTransformation Maven / Gradle / Ivy

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Commercial Edition of the LDAP SDK, which includes all of the general-purpose functionality contained in the Standard Edition, plus additional functionality specific to UnboundID server products.

The newest version!
/*
 * Copyright 2016-2017 UnboundID Corp.
 * All Rights Reserved.
 */
/*
 * Copyright (C) 2016-2017 UnboundID Corp.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk.transformations;



import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.RDN;
import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition;
import com.unboundid.ldap.sdk.schema.Schema;
import com.unboundid.util.Debug;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;



/**
 * This class provides an implementation of an entry transformation that will
 * replace the existing set of values for a given attribute with a value that
 * contains a numeric counter (optionally along with additional static text)
 * that increments for each entry that contains the target attribute.  The
 * resulting attribute will only have a single value, even if it originally had
 * multiple values.
 */
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class ReplaceWithCounterTransformation
       implements EntryTransformation
{
  // The counter to use to obtain the values.
  private final AtomicLong counter;

  // Indicates whether to update the DN of the target entry if its RDN includes
  // the target attribute.
  private final boolean replaceInRDN;

  // The amount by which to increment the counter for each entry.
  private final long incrementAmount;

  // The schema to use when processing.
  private final Schema schema;

  // The names that may be used to reference the attribute to replace.
  private final Set names;

  // The static text that will appear after the number in generated values.
  private final String afterText;

  // The static text that will appear before the number in generated values.
  private final String beforeText;



  /**
   * Creates a new replace with counter transformation using the provided
   * information.
   *
   * @param  schema           The schema to use to identify alternate names for
   *                          the target attribute.  This may be {@code null} if
   *                          a default standard schema should be used.
   * @param  attributeName    The name of the attribute that should be replaced
   *                          with the generated value.
   * @param  initialValue     The initial value to use for the counter.
   * @param  incrementAmount  The amount by which the counter should be
   *                          incremented for each entry containing the target
   *                          attribute.
   * @param  beforeText       An optional string that should appear before the
   *                          counter in generated values.  It may be
   *                          {@code null} if no before text should be used.
   * @param  afterText        An optional string that should appear after the
   *                          counter in generated values.  It may be
   *                          {@code null} if no after text should be used.
   * @param  replaceInRDN     Indicates whether to update the DN of the target
   *                          entry if its RDN includes the target attribute.
   */
  public ReplaceWithCounterTransformation(final Schema schema,
                                          final String attributeName,
                                          final long initialValue,
                                          final long incrementAmount,
                                          final String beforeText,
                                          final String afterText,
                                          final boolean replaceInRDN)
  {
    this.incrementAmount = incrementAmount;
    this.replaceInRDN = replaceInRDN;

    counter = new AtomicLong(initialValue);

    if (beforeText == null)
    {
      this.beforeText = "";
    }
    else
    {
      this.beforeText = beforeText;
    }

    if (afterText == null)
    {
      this.afterText = "";
    }
    else
    {
      this.afterText = afterText;
    }


    // If a schema was provided, then use it.  Otherwise, use the default
    // standard schema.
    Schema s = schema;
    if (s == null)
    {
      try
      {
        s = Schema.getDefaultStandardSchema();
      }
      catch (final Exception e)
      {
        // This should never happen.
        Debug.debugException(e);
      }
    }
    this.schema = s;


    // Get all names that can be used to reference the target attribute.
    final HashSet nameSet = new HashSet(5);
    final String baseName =
         StaticUtils.toLowerCase(Attribute.getBaseName(attributeName));
    nameSet.add(baseName);
    if (s != null)
    {
      final AttributeTypeDefinition at = s.getAttributeType(baseName);
      if (at != null)
      {
        nameSet.add(StaticUtils.toLowerCase(at.getOID()));
        for (final String name : at.getNames())
        {
          nameSet.add(StaticUtils.toLowerCase(name));
        }
      }
    }
    names = Collections.unmodifiableSet(nameSet);
  }



  /**
   * {@inheritDoc}
   */
  public Entry transformEntry(final Entry e)
  {
    if (e == null)
    {
      return null;
    }


    // See if the DN contains the target attribute in the RDN.  If so, then
    // replace its value.
    String dn = e.getDN();
    String newValue = null;
    if (replaceInRDN)
    {
      try
      {
        final DN parsedDN = new DN(dn);
        final RDN rdn = parsedDN.getRDN();
        for (final String name : names)
        {
          if (rdn.hasAttribute(name))
          {
            newValue =
                 beforeText + counter.getAndAdd(incrementAmount) + afterText;
            break;
          }
        }

        if (newValue != null)
        {
          if (rdn.isMultiValued())
          {
            final String[] attrNames = rdn.getAttributeNames();
            final byte[][] originalValues = rdn.getByteArrayAttributeValues();
            final byte[][] newValues = new byte[originalValues.length][];
            for (int i=0; i < attrNames.length; i++)
            {
              if (names.contains(StaticUtils.toLowerCase(attrNames[i])))
              {
                newValues[i] = StaticUtils.getBytes(newValue);
              }
              else
              {
                newValues[i] = originalValues[i];
              }
            }
            dn = new DN(new RDN(attrNames, newValues, schema),
                 parsedDN.getParent()).toString();
          }
          else
          {
            dn = new DN(new RDN(rdn.getAttributeNames()[0], newValue, schema),
                 parsedDN.getParent()).toString();
          }
        }
      }
      catch (final Exception ex)
      {
        Debug.debugException(ex);
      }
    }


    // If the RDN doesn't contain the target attribute, then see if the entry
    // contains the target attribute.  If not, then just return the provided
    // entry.
    if (newValue == null)
    {
      boolean hasAttribute = false;
      for (final String name : names)
      {
        if (e.hasAttribute(name))
        {
          hasAttribute = true;
          break;
        }
      }

      if (! hasAttribute)
      {
        return e;
      }
    }


    // If we haven't computed the new value for this entry, then do so now.
    if (newValue == null)
    {
      newValue = beforeText + counter.getAndAdd(incrementAmount) + afterText;
    }


    // Iterate through the attributes in the entry and make the appropriate
    // updates.
    final Collection originalAttributes = e.getAttributes();
    final ArrayList updatedAttributes =
         new ArrayList(originalAttributes.size());
    for (final Attribute a : originalAttributes)
    {
      if (names.contains(StaticUtils.toLowerCase(a.getBaseName())))
      {
        updatedAttributes.add(new Attribute(a.getName(), schema, newValue));
      }
      else
      {
        updatedAttributes.add(a);
      }
    }


    // Return the updated entry.
    return new Entry(dn, schema, updatedAttributes);
  }



  /**
   * {@inheritDoc}
   */
  public Entry translate(final Entry original, final long firstLineNumber)
  {
    return transformEntry(original);
  }



  /**
   * {@inheritDoc}
   */
  public Entry translateEntryToWrite(final Entry original)
  {
    return transformEntry(original);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy