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

com.phloc.commons.lang.EnumHelper Maven / Gradle / Ivy

There is a newer version: 5.0.0
Show newest version
/**
 * Copyright (C) 2006-2015 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * 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.
 */
package com.phloc.commons.lang;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.phloc.commons.CGlobal;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.PresentForCodeCoverage;
import com.phloc.commons.collections.ArrayHelper;
import com.phloc.commons.id.IHasID;
import com.phloc.commons.id.IHasSimpleIntID;
import com.phloc.commons.name.IHasName;
import com.phloc.commons.state.EChange;
import com.phloc.commons.string.StringHelper;

/**
 * Some enum utility methods.
 * 
 * @author Philip Helger
 */
@Immutable
public final class EnumHelper
{
  private static final Logger s_aLogger = LoggerFactory.getLogger (EnumHelper.class);
  private static final Object [] NOT_CACHABLE = ArrayHelper.EMPTY_OBJECT_ARRAY;
  private static final ReadWriteLock s_aRWLockInt = new ReentrantReadWriteLock ();
  private static final Map  s_aIntCache = new HashMap  ();

  @PresentForCodeCoverage
  @SuppressWarnings ("unused")
  private static final EnumHelper s_aInstance = new EnumHelper ();

  private EnumHelper ()
  {}

  /**
   * Get the enum value with the passed ID
   * 
   * @param 
   *        The ID type
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param aID
   *        The ID to search
   * @return null if no enum item with the given ID is present.
   */
  @Nullable
  public static  & IHasID > ENUMTYPE getFromIDOrNull (@Nonnull final Class  aClass,
                                                                                                         @Nullable final KEYTYPE aID)
  {
    return getFromIDOrDefault (aClass, aID, null);
  }

  /**
   * Get the enum value with the passed ID
   * 
   * @param 
   *        The ID type
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param aID
   *        The ID to search
   * @param aDefault
   *        The default value to be returned, if the ID was not found.
   * @return The default parameter if no enum item with the given ID is present.
   */
  @Nullable
  public static  & IHasID > ENUMTYPE getFromIDOrDefault (@Nonnull final Class  aClass,
                                                                                                            @Nullable final KEYTYPE aID,
                                                                                                            @Nullable final ENUMTYPE aDefault)
  {
    ValueEnforcer.notNull (aClass, "Class");

    if (aID != null)
      for (final ENUMTYPE aElement : aClass.getEnumConstants ())
        if (aElement.getID ().equals (aID))
          return aElement;
    return aDefault;
  }

  /**
   * Get the enum value with the passed ID. If no such ID is present, an
   * {@link IllegalArgumentException} is thrown.
   * 
   * @param 
   *        The ID type
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param aID
   *        The ID to search
   * @return The enum item with the given ID. Never null.
   * @throws IllegalArgumentException
   *         if no enum item with the given ID is present
   */
  @Nonnull
  public static  & IHasID > ENUMTYPE getFromIDOrThrow (@Nonnull final Class  aClass,
                                                                                                          @Nullable final KEYTYPE aID)
  {
    final ENUMTYPE aEnum = getFromIDOrNull (aClass, aID);
    if (aEnum == null)
      throw new IllegalArgumentException ("Failed to resolve ID " + aID + " within class " + aClass);
    return aEnum;
  }

  /**
   * Get the enum value with the passed string ID case insensitive
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sID
   *        The ID to search
   * @return null if no enum item with the given ID is present.
   */
  @Nullable
  public static  & IHasID > ENUMTYPE getFromIDCaseInsensitiveOrNull (@Nonnull final Class  aClass,
                                                                                                              @Nullable final String sID)
  {
    return getFromIDCaseInsensitiveOrDefault (aClass, sID, null);
  }

  /**
   * Get the enum value with the passed string ID case insensitive
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sID
   *        The ID to search
   * @param aDefault
   *        The default value to be returned, if the ID was not found.
   * @return The default parameter if no enum item with the given ID is present.
   */
  @Nullable
  public static  & IHasID > ENUMTYPE getFromIDCaseInsensitiveOrDefault (@Nonnull final Class  aClass,
                                                                                                                 @Nullable final String sID,
                                                                                                                 @Nullable final ENUMTYPE aDefault)
  {
    ValueEnforcer.notNull (aClass, "Class");

    if (sID != null)
      for (final ENUMTYPE aElement : aClass.getEnumConstants ())
        if (aElement.getID ().equalsIgnoreCase (sID))
          return aElement;
    return aDefault;
  }

  /**
   * Get the enum value with the passed string ID (case insensitive). If no such
   * ID is present, an {@link IllegalArgumentException} is thrown.
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sID
   *        The ID to search
   * @return The enum item with the given ID. Never null.
   * @throws IllegalArgumentException
   *         if no enum item with the given ID is present
   */
  @Nonnull
  public static  & IHasID > ENUMTYPE getFromIDCaseInsensitiveOrThrow (@Nonnull final Class  aClass,
                                                                                                               @Nullable final String sID)
  {
    final ENUMTYPE aEnum = getFromIDCaseInsensitiveOrNull (aClass, sID);
    if (aEnum == null)
      throw new IllegalArgumentException ("Failed to resolve ID " + sID + " within class " + aClass);
    return aEnum;
  }

  /**
   * Get the enum value with the passed ID
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param nID
   *        The ID to search
   * @return null if no enum item with the given ID is present.
   */
  @Nullable
  public static  & IHasSimpleIntID> ENUMTYPE getFromIDOrNull (@Nonnull final Class  aClass,
                                                                                               final int nID)
  {
    return getFromIDOrDefault (aClass, nID, null);
  }

  /**
   * Get the enum value with the passed ID
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param nID
   *        The ID to search
   * @param aDefault
   *        The default value to be returned, if the ID was not found.
   * @return The default parameter if no enum item with the given ID is present.
   */
  @Nullable
  public static  & IHasSimpleIntID> ENUMTYPE getFromIDOrDefault (@Nonnull final Class  aClass,
                                                                                                  final int nID,
                                                                                                  @Nullable final ENUMTYPE aDefault)
  {
    ValueEnforcer.notNull (aClass, "Class");

    final String sCacheKey = aClass.getName ();
    Object [] aCachedData;
    s_aRWLockInt.readLock ().lock ();
    try
    {
      aCachedData = s_aIntCache.get (sCacheKey);
    }
    finally
    {
      s_aRWLockInt.readLock ().unlock ();
    }
    if (aCachedData == null)
    {
      s_aRWLockInt.writeLock ().lock ();
      try
      {
        // Try again in write lock
        aCachedData = s_aIntCache.get (sCacheKey);
        if (aCachedData == null)
        {
          // Create new cache entry
          int nMinID = Integer.MAX_VALUE;
          int nMaxID = Integer.MIN_VALUE;
          for (final ENUMTYPE aElement : aClass.getEnumConstants ())
          {
            final int nElementID = aElement.getID ();
            if (nElementID < nMinID)
              nMinID = nElementID;
            if (nElementID > nMaxID)
              nMaxID = nElementID;
          }
          if (nMinID >= 0 && nMaxID <= CGlobal.MAX_BYTE_VALUE)
          {
            // Cachable!
            aCachedData = new Object [nMaxID + 1];
            for (final ENUMTYPE aElement : aClass.getEnumConstants ())
              aCachedData[aElement.getID ()] = aElement;
          }
          else
          {
            // Enum not cachable
            aCachedData = NOT_CACHABLE;
          }
          s_aIntCache.put (sCacheKey, aCachedData);
        }
      }
      finally
      {
        s_aRWLockInt.writeLock ().unlock ();
      }
    }

    if (aCachedData != NOT_CACHABLE)
    {
      if (nID < 0 || nID >= aCachedData.length)
        return aDefault;
      return GenericReflection. uncheckedCast (aCachedData[nID]);
    }

    // Object is not cachable - traverse as ususal
    for (final ENUMTYPE aElement : aClass.getEnumConstants ())
      if (aElement.getID () == nID)
        return aElement;
    return aDefault;
  }

  /**
   * Get the enum value with the passed ID. If no such ID is present, an
   * {@link IllegalArgumentException} is thrown.
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param nID
   *        The ID to search
   * @return The enum item with the given ID. Never null.
   * @throws IllegalArgumentException
   *         if no enum item with the given ID is present
   */
  @Nonnull
  public static  & IHasSimpleIntID> ENUMTYPE getFromIDOrThrow (@Nonnull final Class  aClass,
                                                                                                final int nID)
  {
    final ENUMTYPE aEnum = getFromIDOrNull (aClass, nID);
    if (aEnum == null)
      throw new IllegalArgumentException ("Failed to resolve ID " + nID + " within class " + aClass);
    return aEnum;
  }

  /**
   * Get the enum value with the passed name
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sName
   *        The name to search
   * @return null if no enum item with the given name is present.
   */
  @Nullable
  public static  & IHasName> ENUMTYPE getFromNameOrNull (@Nonnull final Class  aClass,
                                                                                          @Nullable final String sName)
  {
    return getFromNameOrDefault (aClass, sName, null);
  }

  /**
   * Get the enum value with the passed name
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sName
   *        The name to search
   * @param aDefault
   *        The default value to be returned, if the name was not found.
   * @return The default parameter if no enum item with the given name is
   *         present.
   */
  @Nullable
  public static  & IHasName> ENUMTYPE getFromNameOrDefault (@Nonnull final Class  aClass,
                                                                                             @Nullable final String sName,
                                                                                             @Nullable final ENUMTYPE aDefault)
  {
    ValueEnforcer.notNull (aClass, "Class");

    if (StringHelper.hasText (sName))
      for (final ENUMTYPE aElement : aClass.getEnumConstants ())
        if (aElement.getName ().equals (sName))
          return aElement;
    return aDefault;
  }

  /**
   * Get the enum value with the passed name. If no such name is present, an
   * {@link IllegalArgumentException} is thrown.
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sName
   *        The name to search
   * @return The enum item with the given name. Never null.
   * @throws IllegalArgumentException
   *         if no enum item with the given name is present
   */
  @Nonnull
  public static  & IHasName> ENUMTYPE getFromNameOrThrow (@Nonnull final Class  aClass,
                                                                                           @Nullable final String sName)
  {
    final ENUMTYPE aEnum = getFromNameOrNull (aClass, sName);
    if (aEnum == null)
      throw new IllegalArgumentException ("Failed to resolve name " + sName + " within class " + aClass);
    return aEnum;
  }

  /**
   * Get the enum value with the passed name case insensitive
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sName
   *        The name to search
   * @return null if no enum item with the given ID is present.
   */
  @Nullable
  public static  & IHasName> ENUMTYPE getFromNameCaseInsensitiveOrNull (@Nonnull final Class  aClass,
                                                                                                         @Nullable final String sName)
  {
    return getFromNameCaseInsensitiveOrDefault (aClass, sName, null);
  }

  /**
   * Get the enum value with the passed name case insensitive
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sName
   *        The name to search
   * @param aDefault
   *        The default value to be returned, if the name was not found.
   * @return The default parameter if no enum item with the given name is
   *         present.
   */
  @Nullable
  public static  & IHasName> ENUMTYPE getFromNameCaseInsensitiveOrDefault (@Nonnull final Class  aClass,
                                                                                                            @Nullable final String sName,
                                                                                                            @Nullable final ENUMTYPE aDefault)
  {
    ValueEnforcer.notNull (aClass, "Class");

    if (StringHelper.hasText (sName))
      for (final ENUMTYPE aElement : aClass.getEnumConstants ())
        if (aElement.getName ().equalsIgnoreCase (sName))
          return aElement;
    return aDefault;
  }

  /**
   * Get the enum value with the passed name (case insensitive). If no such name
   * is present, an {@link IllegalArgumentException} is thrown.
   * 
   * @param 
   *        The enum type
   * @param aClass
   *        The enum class
   * @param sName
   *        The name to search
   * @return The enum item with the given name. Never null.
   * @throws IllegalArgumentException
   *         if no enum item with the given name is present
   */
  @Nonnull
  public static  & IHasName> ENUMTYPE getFromNameCaseInsensitiveOrThrow (@Nonnull final Class  aClass,
                                                                                                          @Nullable final String sName)
  {
    final ENUMTYPE aEnum = getFromNameCaseInsensitiveOrNull (aClass, sName);
    if (aEnum == null)
      throw new IllegalArgumentException ("Failed to resolve name " + sName + " within class " + aClass);
    return aEnum;
  }

  /**
   * Get the unique name of the passed enum entry.
   * 
   * @param aEnum
   *        The enum to use. May not be null.
   * @return The unique ID as a combination of the class name and the enum entry
   *         name. Never null.
   */
  @Nonnull
  public static String getEnumID (@Nonnull final Enum  aEnum)
  {
    // No explicit null check, because this method is used heavily in pdaf
    // locale resolving, so we want to spare some CPU cycles :)
    return aEnum.getClass ().getName () + '.' + aEnum.name ();
  }

  @Nonnull
  public static EChange clearCache ()
  {
    s_aRWLockInt.writeLock ().lock ();
    try
    {
      if (s_aIntCache.isEmpty ())
        return EChange.UNCHANGED;
      s_aIntCache.clear ();
      if (s_aLogger.isDebugEnabled ())
        s_aLogger.debug ("Cache was cleared: " + EnumHelper.class.getName ());
      return EChange.CHANGED;
    }
    finally
    {
      s_aRWLockInt.writeLock ().unlock ();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy