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

com.unboundid.ldap.sdk.persist.PersistUtils Maven / Gradle / Ivy

/*
 * Copyright 2009-2020 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2009-2020 Ping Identity Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (C) 2009-2020 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.NotNull;
import com.unboundid.util.Nullable;
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(@NotNull final String s,
                                        @NotNull 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(@NotNull final String s,
                                        final boolean o,
                                        @NotNull 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(@NotNull final String b,
                                          @NotNull final String o,
                                          @NotNull 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(@NotNull final String s,
                                              @NotNull 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.
   */
  @NotNull()
  public static String toJavaIdentifier(@NotNull 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.
   */
  @Nullable()
  public static  T getEntryAsObject(@NotNull final DN dn,
                                       @NotNull final Class type,
                                       @NotNull 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.
   */
  @NotNull()
  public static  PersistedObjects getEntriesAsObjects(
                                             @NotNull final DN[] dns,
                                             @NotNull final Class type,
                                             @NotNull 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