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

com.unboundid.ldap.sdk.persist.PersistUtils 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 Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

There is a newer version: 7.0.2
Show newest version
/*
 * Copyright 2009-2018 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright (C) 2009-2018 Ping Identity Corporation
 *
 * 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.persist;



import java.util.UUID;

import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.DNEntrySource;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;

import static com.unboundid.ldap.sdk.persist.PersistMessages.*;



/**
 * This class provides a set of utilities that may be used in the course of
 * persistence processing.
 */
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class PersistUtils
{
  /**
   * Prevent this utility class from being instantiated.
   */
  private PersistUtils()
  {
    // No implementation required.
  }



  /**
   * Indicates whether the provided string could be used as a valid attribute or
   * object class name.  Numeric OIDs will also be considered acceptable.
   *
   * @param  s  The string for which to make the determination.
   * @param  r  A buffer to which the unacceptable reason may be appended.  It
   *            must not be {@code null}.
   *
   * @return  {@code true} if the provided string is acceptable for use as an
   *          LDAP attribute or object class name, or {@code false} if not.
   */
  public static boolean isValidLDAPName(final String s, final StringBuilder r)
  {
    return isValidLDAPName(s, false, r);
  }



  /**
   * Indicates whether the provided string could be used as a valid attribute or
   * object class name.  Numeric OIDs will also be considered acceptable.
   *
   * @param  s  The string for which to make the determination.
   * @param  o  Indicates whether the name should be allowed to contain
   *            attribute options (e.g., a semicolon with one or more valid
   *            characters after it).
   * @param  r  A buffer to which the unacceptable reason may be appended.  It
   *            must not be {@code null}.
   *
   * @return  {@code true} if the provided string is acceptable for use as an
   *          LDAP attribute or object class name, or {@code false} if not.
   */
  public static boolean isValidLDAPName(final String s, final boolean o,
                                        final StringBuilder r)
  {
    int length;
    if ((s == null) || ((length = s.length()) == 0))
    {
      r.append(ERR_LDAP_NAME_VALIDATOR_EMPTY.get());
      return false;
    }

    final String baseName;
    final int semicolonPos = s.indexOf(';');
    if (semicolonPos > 0)
    {
      if (! o)
      {
        r.append(ERR_LDAP_NAME_VALIDATOR_INVALID_CHAR.get(s, ';',
             semicolonPos));
        return false;
      }

      baseName = s.substring(0, semicolonPos);
      length = baseName.length();

      final String optionsStr = s.substring(semicolonPos+1);
      if (! isValidOptionSet(baseName, optionsStr, r))
      {
        return false;
      }
    }
    else
    {
      baseName = s;
    }

    if (StaticUtils.isNumericOID(baseName))
    {
      return true;
    }

    for (int i=0; i < length; i++)
    {
      final char c = baseName.charAt(i);
      if (((c >= 'a') && (c <= 'z')) ||
          ((c >= 'A') && (c <= 'Z')))
      {
        // This will always be acceptable.
      }
      else if (((c >= '0') && (c <= '9')) || (c == '-'))
      {
        // This will be acceptable for all but the first character.
        if (i == 0)
        {
          r.append(ERR_LDAP_NAME_VALIDATOR_INVALID_FIRST_CHAR.get(s));
          return false;
        }
      }
      else
      {
        r.append(ERR_LDAP_NAME_VALIDATOR_INVALID_CHAR.get(s, c, i));
        return false;
      }
    }

    return true;
  }



  /**
   * Indicates whether the provided string represents a valid set of attribute
   * options.  It should not contain the initial semicolon.
   *
   * @param  b  The base name for the attribute, without the option string or
   *            the semicolon used to delimit the option string from the base
   *            name.
   * @param  o  The option string to examine.  It must not be {@code null}, and
   *            must not contain the initial semicolon.
   * @param  r  A buffer to which the unacceptable reason may be appended.  It
   *            must not be {@code null}.
   *
   * @return  {@code true} if the provided string represents a valid set of
   *          options, or {@code false} if not.
   */
  private static boolean isValidOptionSet(final String b, final String o,
                                          final StringBuilder r)
  {
    boolean lastWasSemicolon = true;

    for (int i=0; i < o.length(); i++)
    {
      final char c = o.charAt(i);
      if (c == ';')
      {
        if (lastWasSemicolon)
        {
          r.append(
               ERR_LDAP_NAME_VALIDATOR_OPTION_WITH_CONSECUTIVE_SEMICOLONS.get(
                    b + ';' + o));
          return false;
        }
        else
        {
          lastWasSemicolon = true;
        }
      }
      else
      {
        lastWasSemicolon = false;
        if (((c >= 'a') && (c <= 'z')) ||
            ((c >= 'A') && (c <= 'Z')) ||
            ((c >= '0') && (c <= '9')) ||
            (c == '-'))
        {
          // This will always be acceptable.
        }
        else
        {
          r.append(ERR_LDAP_NAME_VALIDATOR_INVALID_OPTION_CHAR.get(
               (b + ';' + o), c, (b.length() + 1 + i)));
          return false;
        }
      }
    }

    if (lastWasSemicolon)
    {
      r.append(ERR_LDAP_NAME_VALIDATOR_ENDS_WITH_SEMICOLON.get(b + ';' + o));
      return false;
    }

    return true;
  }



  /**
   * Indicates whether the provided string could be used as a valid Java
   * identifier.  The identifier must begin with an ASCII letter or underscore,
   * and must contain only ASCII letters, ASCII digits, and the underscore
   * character.  Even though a dollar sign is technically allowed, it will not
   * be considered valid for the purpose of this method.  Similarly, even though
   * Java keywords are not allowed, they will not be rejected by this method.
   *
   * @param  s  The string for which to make the determination.  It must not be
   *            {@code null}.
   * @param  r  A buffer to which the unacceptable reason may be appended.  It
   *            must not be {@code null}.
   *
   * @return  {@code true} if the provided string is acceptable for use as a
   *          Java identifier, or {@code false} if not.
   */
  public static boolean isValidJavaIdentifier(final String s,
                                              final StringBuilder r)
  {
    final int length = s.length();
    for (int i=0; i < length; i++)
    {
      final char c = s.charAt(i);
      if (((c >= 'a') && (c <= 'z')) ||
          ((c >= 'A') && (c <= 'Z')) ||
          (c == '_'))
      {
        // This will always be acceptable.
      }
      else if ((c >= '0') && (c <= '9'))
      {
        if (i == 0)
        {
          r.append(ERR_JAVA_NAME_VALIDATOR_INVALID_FIRST_CHAR_DIGIT.get(s));
          return false;
        }
      }
      else
      {
        r.append(ERR_JAVA_NAME_VALIDATOR_INVALID_CHAR.get(s, c, i));
        return false;
      }
    }

    return true;
  }



  /**
   * Transforms the provided string if necessary so that it may be used as a
   * valid Java identifier.  If the provided string is already a valid Java
   * identifier, then it will be returned as-is.  Otherwise, it will be
   * transformed to make it more suitable.
   *
   * @param  s  The attribute or object class name to be converted to a Java
   *            identifier.
   *
   * @return  A string that may be used as a valid Java identifier.
   */
  public static String toJavaIdentifier(final String s)
  {
    final int length;
    if ((s == null) || ((length = s.length()) == 0))
    {
      // This will be ugly, but safe.
      return toJavaIdentifier(UUID.randomUUID().toString());
    }

    boolean nextUpper = false;
    final StringBuilder b = new StringBuilder(length);
    for (int i=0; i < length; i++)
    {
      final char c = s.charAt(i);
      if (((c >= 'a') && (c <= 'z')) ||
          ((c >= 'A') && (c <= 'Z')))
      {
        if (nextUpper)
        {
          b.append(Character.toUpperCase(c));
        }
        else
        {
          b.append(c);
        }

        nextUpper = false;
      }
      else if ((c >= '0') && (c <= '9'))
      {
        if (i == 0)
        {
          // Java identifiers can't begin with a digit, but they can begin with
          // an underscore followed by a digit, so we'll use that instead.
          b.append('_');
        }

        b.append(c);
        nextUpper = false;
      }
      else
      {
        // If the provided string was a valid LDAP attribute or object class
        // name, then this should be a dash, but we'll be safe and take the same
        // action for any remaining character.
        nextUpper = true;
      }
    }

    if (b.length() == 0)
    {
      // This should only happen if the provided string wasn't a valid LDAP
      // attribute or object class name to start with.
      return toJavaIdentifier(UUID.randomUUID().toString());
    }

    return b.toString();
  }



  /**
   * Retrieves the entry with the specified DN and decodes it as an object of
   * the specified type.
   *
   * @param    The type of object as which to decode the entry.
   *
   * @param  dn    The DN of the entry to retrieve.  It must not be
   *               {@code null}.
   * @param  type  The type of object as which the entry should be decoded.  It
   *               must not be {@code null}, and the class must be marked with
   *               the {@link LDAPObject} annotation type.
   * @param  conn  The connection that should be used to retrieve the entry.  It
   *               must not be {@code null}.
   *
   * @return  The object decoded from the specified entry, or {@code null} if
   *          the entry cannot be retrieved (e.g., because it does not exist or
   *          is not readable by the authenticated user).
   *
   * @throws  LDAPException  If a problem occurs while trying to retrieve the
   *                         entry or decode it as the specified type of object.
   */
  public static  T getEntryAsObject(final DN dn, final Class type,
                                       final LDAPInterface conn)
         throws LDAPException
  {
    Validator.ensureNotNull(dn, type, conn);

    final LDAPPersister p = LDAPPersister.getInstance(type);

    final Entry e = conn.getEntry(dn.toString(),
         p.getObjectHandler().getAttributesToRequest());
    if (e == null)
    {
      return null;
    }

    return p.decode(e);
  }



  /**
   * Retrieves and decodes the indicated entries as objects of the specified
   * type.
   *
   * @param    The type of object as which to decode the entries.
   *
   * @param  dns   The DNs of the entries to retrieve.  It must not be
   *               {@code null}.
   * @param  type  The type of object as which the entries should be decoded.
   *               It must not be {@code null}, and the class must be marked
   *               with the {@link LDAPObject} annotation type.
   * @param  conn  The connection that should be used to retrieve the entries.
   *               It must not be {@code null}.
   *
   * @return  A {@code PersistedObjects} result that may be used to access the
   *          objects decoded from the provided set of DNs.
   *
   * @throws  LDAPPersistException  If the requested type cannot be used with
   *                                the LDAP SDK persistence framework.
   */
  public static  PersistedObjects getEntriesAsObjects(final DN[] dns,
                                             final Class type,
                                             final LDAPInterface conn)
         throws LDAPPersistException
  {
    Validator.ensureNotNull(dns, type, conn);

    final LDAPPersister p = LDAPPersister.getInstance(type);

    final DNEntrySource entrySource = new DNEntrySource(conn, dns,
         p.getObjectHandler().getAttributesToRequest());
    return new PersistedObjects<>(p, entrySource);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy