/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.cache;

import java.util.Optional;

import org.apache.geode.cache.configuration.EnumActionDestroyOverflow;
import org.apache.geode.cache.configuration.RegionAttributesType;
import org.apache.geode.cache.control.ResourceManager;
import org.apache.geode.cache.util.ObjectSizer;
import org.apache.geode.internal.cache.EvictionAttributesImpl;

/**
 * <p>
 * Attributes that describe how a <code>Region</code>'s size is managed through an eviction
 * controller. Eviction controllers are defined by an
 * {@link org.apache.geode.cache.EvictionAlgorithm} and a
 * {@link org.apache.geode.cache.EvictionAction}. Once a <code>Region</code> is created with an
 * eviction controller, it can not be removed, however it can be changed through an
 * {@link org.apache.geode.cache.EvictionAttributesMutator}.
 *
 * @see org.apache.geode.cache.AttributesFactory#setEvictionAttributes(EvictionAttributes)
 * @see org.apache.geode.cache.AttributesMutator
 * @since GemFire 5.0
 */
public abstract class EvictionAttributes {
  /**
   * The default maximum for {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU}. Currently
   * <code>900</code> entries.
   */
  public static final int DEFAULT_ENTRIES_MAXIMUM = 900;
  /**
   * The default maximum for {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU}. Currently
   * <code>10</code> megabytes.
   */
  public static final int DEFAULT_MEMORY_MAXIMUM = 10;

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with
   * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default
   * {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum}.
   * <p>
   * {@link EvictionAttributes} cause regions to evict the least recently used (LRU) entry once the
   * region reaches a maximum capacity. The entry is either locally destroyed or its value overflows
   * to disk when evicted.
   * <p>
   * This is not supported when replication is enabled.
   * <p>
   * For a region with {@link DataPolicy#PARTITION}, the EvictionAttribute <code>maximum</code>,
   * indicates the number of entries allowed in the region, collectively for its primary buckets and
   * redundant copies for this JVM. Once there are <code>maximum</code> entries in the region's
   * primary buckets and redundant copies for this JVM, the least recently used entry will be
   * evicted from the bucket in which the subsequent put takes place.
   * <p>
   * If you are using a <code>cache.xml</code> file to create a Cache Region declaratively, you can
   * include the following to configure a region for eviction
   *
   * <pre>
   *         &lt;region-attributes&gt;
   *            &lt;eviction-attributes&gt;
   *               &lt;lru-entry-count maximum=&quot;900&quot; action=&quot;local-destroy&quot;/&gt;
   *            &lt;/eviction-attributes&gt;
   *         &lt;/region-attributes&gt;
   * </pre>
   *
   * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default
   *         {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum}
   */
  public static EvictionAttributes createLRUEntryAttributes() {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setMaximum(DEFAULT_ENTRIES_MAXIMUM);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with
   * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and given
   * <code>maximumEntries</code>.
   *
   * @param maximumEntries the number of entries to keep in the Region
   * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and
   *         <code>maximumEntries</code>
   * @see #createLRUEntryAttributes()
   */
  public static EvictionAttributes createLRUEntryAttributes(int maximumEntries) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setMaximum(maximumEntries);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with
   * default {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum} and given <code>evictionAction</code>.
   *
   * @param evictionAction the action to perform when evicting an entry
   * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with default
   *         {@linkplain #DEFAULT_ENTRIES_MAXIMUM maximum} and given <code>evictionAction</code>
   * @see #createLRUEntryAttributes()
   * @since GemFire 8.1
   */
  public static EvictionAttributes createLRUEntryAttributes(EvictionAction evictionAction) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY)
        .setAction(evictionAction).setMaximum(DEFAULT_ENTRIES_MAXIMUM);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with
   * given <code>evictionAction</code> and given <code>maximumEntries</code>.
   *
   * @param maximumEntries the number of entries to keep in the Region
   * @param evictionAction the action to perform when evicting an entry
   * @return {@linkplain EvictionAlgorithm#LRU_ENTRY entry LRU} eviction attributes with given
   *         <code>evictionAction</code> and given <code>maximumEntries</code>
   * @see #createLRUEntryAttributes()
   */
  public static EvictionAttributes createLRUEntryAttributes(int maximumEntries,
      EvictionAction evictionAction) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_ENTRY)
        .setAction(evictionAction).setMaximum(maximumEntries);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with
   * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default
   * {@linkplain ObjectSizer#DEFAULT sizer}.
   * <p>
   * Heap LRU EvictionAttributes evict the least recently used {@link Region.Entry} when heap usage
   * exceeds the {@link ResourceManager} eviction heap threshold. If the eviction heap threshold is
   * exceeded the least recently used {@link Region.Entry}s are evicted.
   * <p>
   * With other LRU-based eviction controllers, only cache actions (such as
   * {@link Region#put(Object, Object) puts} and {@link Region#get(Object) gets}) cause the LRU
   * entry to be evicted. However, with heap LRU, because the JVM's heap may be effected by more
   * than just the GemFire cache operations, a daemon thread will perform the eviction if no
   * operations are being done on the region.
   * <p>
   * The eviction attribute's {@linkplain ObjectSizer sizer} is used to estimate how much the heap
   * will be reduced by an eviction.
   * <p>
   * When using Heap LRU, the JVM must be launched with the <code>-Xmx</code> and <code>-Xms</code>
   * switches set to the same values. Many virtual machine implementations have additional JVM
   * switches to control the behavior of the garbage collector. We suggest that you investigate
   * tuning the garbage collector when using this type of eviction controller. A collector that
   * frequently collects is needed to keep our heap usage up to date. In particular, on the Sun
   * <A href="http://java.sun.com/docs/hotspot/gc/index.html">HotSpot</a> JVM,
   * before Java 14,
   * the <code>-XX:+UseConcMarkSweepGC</code> flag needs to be set, and
   * <code>-XX:CMSInitiatingOccupancyFraction=N</code> should be set with N being a percentage that
   * is less than the {@link ResourceManager} eviction heap threshold.
   * <p>
   * The JRockit JVM has similar flags, <code>-Xgc:gencon</code> and <code>-XXgcTrigger:N</code>,
   * which are required if using this LRU algorithm. Please Note: the JRockit gcTrigger flag is
   * based on heap free, not heap in use like the GemFire parameter. This means you need to set
   * gcTrigger to 100-N. for example, if your eviction threshold is 30 percent, you will need to set
   * gcTrigger to 70 percent.
   * <p>
   * On the IBM JVM, the flag to get a similar collector is <code>-Xgcpolicy:gencon</code>, but
   * there is no corollary to the gcTrigger/CMSInitiatingOccupancyFraction flags, so when using this
   * feature with an IBM JVM, the heap usage statistics might lag the true memory usage of the JVM,
   * and thresholds may need to be set sufficiently high that the JVM will initiate GC before the
   * thresholds are crossed.
   * <p>
   * If you are using a <code>cache.xml</code> file to create a Cache Region declaratively, you can
   * include the following to create an LRU heap eviction controller:
   *
   * <pre>
   *         &lt;region-attributes&gt;
   *            &lt;eviction-attributes&gt;
   *               &lt;lru-heap-percentage action=&quot;local-destroy&quot;
   *            &lt;/eviction-attributes&gt;
   *         &lt;/region-attributes&gt;
   * </pre>
   * <p>
   *
   * @return {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and default
   *         {@linkplain ObjectSizer#DEFAULT sizer}
   */
  public static EvictionAttributes createLRUHeapAttributes() {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_HEAP)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setObjectSizer(ObjectSizer.DEFAULT);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with
   * default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and the given
   * <code>sizer</code>.
   *
   * @param sizer the sizer implementation used to determine the size of each entry in this region
   * @return {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action} and the given
   *         <code>sizer</code>
   * @see #createLRUHeapAttributes()
   */
  public static EvictionAttributes createLRUHeapAttributes(final ObjectSizer sizer) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_HEAP)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setObjectSizer(sizer);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with
   * the given <code>evictionAction</code> and given <code>sizer</code>.
   *
   * @param sizer the sizer implementation used to determine the size of each entry in this region
   * @param evictionAction the way in which entries should be evicted
   * @return {@linkplain EvictionAlgorithm#LRU_HEAP heap LRU} eviction attributes with the given
   *         <code>evictionAction</code> and given <code>sizer</code>
   * @see #createLRUHeapAttributes()
   */
  public static EvictionAttributes createLRUHeapAttributes(final ObjectSizer sizer,
      final EvictionAction evictionAction) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_HEAP)
        .setAction(evictionAction).setObjectSizer(sizer);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes
   * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default
   * {@linkplain ObjectSizer#DEFAULT sizer}, and default {@linkplain #DEFAULT_MEMORY_MAXIMUM
   * maximum}.
   * <p>
   * Creates EvictionAttributes for an eviction controller that will remove the least recently used
   * (LRU) entry from a region once the region reaches a certain byte capacity. Capacity is
   * determined by monitoring the size of entries added and evicted. Capacity is specified in terms
   * of megabytes. GemFire uses an efficient algorithm to determine the amount of space a region
   * entry occupies in the JVM. However, this algorithm may not yield optimal results for all kinds
   * of data. The user may provide their own algorithm for determining the size of objects by
   * implementing an {@link ObjectSizer}.
   * <p>
   * For a region with {@link DataPolicy#PARTITION}, the EvictionAttribute <code>maximum</code>, is
   * always equal to {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "}
   * specified for the {@link PartitionAttributes}. It signifies the amount of memory allowed in the
   * region, collectively for its primary buckets and redundant copies for this JVM. It can be
   * different for the same region in different JVMs.
   * <p>
   * If you are using a <code>cache.xml</code> file to create a Cache Region declaratively, you can
   * include the following to create an LRU memory eviction controller:
   *
   * <pre>
   *          &lt;region-attributes&gt;
   *            &lt;eviction-attributes&gt;
   *               &lt;lru-memory-size maximum=&quot;10&quot; action=&quot;local-destroy&quot;&gt;
   *                  &lt;class-name&gt;com.foo.MySizer&lt;/class-name&gt;
   *                  &lt;parameter name=&quot;name&quot;&gt;
   *                     &lt;string&gt;Super Sizer&lt;/string&gt;
   *                  &lt;/parameter&gt;
   *               &lt;/lru-memory-size&gt;
   *            &lt;/eviction-attributes&gt;
   *         &lt;/region-attributes&gt;
   * </pre>
   *
   * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default
   *         {@linkplain ObjectSizer#DEFAULT sizer}, and default {@linkplain #DEFAULT_MEMORY_MAXIMUM
   *         maximum}
   */
  public static EvictionAttributes createLRUMemoryAttributes() {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setMaximum(DEFAULT_MEMORY_MAXIMUM)
        .setObjectSizer(ObjectSizer.DEFAULT);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes
   * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default
   * {@linkplain ObjectSizer#DEFAULT sizer}, and given <code>maximumMegabytes</code>.
   * <p>
   * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the
   * EvictionAttribute <code>maximum</code>, is always set to
   * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for
   * the {@link PartitionAttributes}.
   * <p>
   *
   * @param maximumMegabytes the maximum allowed bytes in the Region
   * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, default
   *         {@linkplain ObjectSizer#DEFAULT sizer}, and given <code>maximumMegabytes</code>
   * @see #createLRUMemoryAttributes()
   */
  public static EvictionAttributes createLRUMemoryAttributes(int maximumMegabytes) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setMaximum(maximumMegabytes)
        .setObjectSizer(null);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes
   * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given
   * <code>sizer</code>, and given <code>maximumMegabytes</code>.
   * <p>
   * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the
   * EvictionAttribute <code>maximum</code>, is always set to
   * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for
   * the {@link PartitionAttributes}.
   *
   * @param maximumMegabytes the maximum allowed bytes in the Region
   * @param sizer calculates the size in bytes of the key and value for an entry.
   * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given <code>sizer</code>,
   *         and given <code>maximumMegabytes</code>
   * @see #createLRUMemoryAttributes()
   */
  public static EvictionAttributes createLRUMemoryAttributes(int maximumMegabytes,
      ObjectSizer sizer) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setMaximum(maximumMegabytes)
        .setObjectSizer(sizer);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes
   * with the given <code>evictionAction</code>, given <code>sizer</code>, and given
   * <code>maximumMegabytes</code>.
   * <p>
   * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the
   * EvictionAttribute <code>maximum</code>, is always set to
   * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for
   * the {@link PartitionAttributes}.
   *
   * @param maximumMegabytes the maximum allowed bytes in the Region
   * @param sizer calculates the size in bytes of the key and value for an entry.
   * @param evictionAction the action to take when the maximum has been reached.
   * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with the given
   *         <code>evictionAction</code>, given <code>sizer</code>, and given
   *         <code>maximumMegabytes</code>
   * @see #createLRUMemoryAttributes()
   */
  public static EvictionAttributes createLRUMemoryAttributes(int maximumMegabytes,
      ObjectSizer sizer, EvictionAction evictionAction) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY)
        .setAction(evictionAction).setMaximum(maximumMegabytes).setObjectSizer(sizer);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes
   * with default {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given
   * <code>sizer</code>, and default {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum}.
   * <p>
   * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the
   * EvictionAttribute <code>maximum</code>, is always set to
   * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for
   * the {@link PartitionAttributes}.
   *
   * @param sizer calculates the size in bytes of the key and value for an entry.
   * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with default
   *         {@linkplain EvictionAction#DEFAULT_EVICTION_ACTION action}, given <code>sizer</code>,
   *         and default {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum}
   * @see #createLRUMemoryAttributes()
   * @since GemFire 6.0
   */
  public static EvictionAttributes createLRUMemoryAttributes(ObjectSizer sizer) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY)
        .setAction(EvictionAction.DEFAULT_EVICTION_ACTION).setObjectSizer(sizer)
        .setMaximum(DEFAULT_MEMORY_MAXIMUM);
  }

  /**
   * Creates and returns {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes
   * with given <code>evictionAction</code>, given <code>sizer</code>, and default
   * {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum}.
   * <p>
   * For a region with {@link DataPolicy#PARTITION}, even if maximumMegabytes are supplied, the
   * EvictionAttribute <code>maximum</code>, is always set to
   * {@link PartitionAttributesFactory#setLocalMaxMemory(int) " local max memory "} specified for
   * the {@link PartitionAttributes}.
   *
   * @param sizer calculates the size in bytes of the key and value for an entry.
   * @param evictionAction the action to take when the maximum has been reached.
   * @return {@linkplain EvictionAlgorithm#LRU_MEMORY memory LRU} eviction attributes with given
   *         <code>evictionAction</code>, given <code>sizer</code>, and default
   *         {@linkplain #DEFAULT_MEMORY_MAXIMUM maximum}
   * @see #createLRUMemoryAttributes()
   * @since GemFire 6.0
   */
  public static EvictionAttributes createLRUMemoryAttributes(ObjectSizer sizer,
      EvictionAction evictionAction) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LRU_MEMORY)
        .setAction(evictionAction).setObjectSizer(sizer).setMaximum(DEFAULT_MEMORY_MAXIMUM);
  }

  /**
   * An {@link ObjectSizer} is used by the {@link EvictionAlgorithm#LRU_MEMORY} algorithm to measure
   * the size of each Entry as it is entered into a Region. A default implementation is provided,
   * see {@link #createLRUMemoryAttributes()} for more. An {@link ObjectSizer} is used by
   * {@link EvictionAlgorithm#LRU_HEAP} to estimate how much heap will be saved when evicting a
   * region entry.
   *
   * @return the sizer used by {@link EvictionAlgorithm#LRU_MEMORY} or
   *         {@link EvictionAlgorithm#LRU_HEAP}, for all other algorithms null is returned.
   */
  public abstract ObjectSizer getObjectSizer();

  /**
   * The algorithm is used to identify entries that will be evicted.
   *
   * @return a non-null EvictionAlgorithm instance reflecting the configured value or NONE when no
   *         eviction controller has been configured.
   */
  public abstract EvictionAlgorithm getAlgorithm();

  /**
   * The unit of this value is determined by the definition of the {@link EvictionAlgorithm} set by
   * one of the creation methods e.g. {@link EvictionAttributes#createLRUEntryAttributes()}.
   * <ul>
   * <li>If the algorithm is LRU_ENTRY then the unit is entries.
   * <li>If the algorithm is LRU_MEMORY then the unit is megabytes.
   * <li>If the algorithm is LRU_HEAP then the unit is undefined and this method always returns
   * zero.
   * Note, in geode 1.4 and earlier, this method would throw UnsupportedOperationException for
   * LRU_HEAP.
   * </ul>
   *
   * @return maximum value used by the {@link EvictionAlgorithm} which determines when the
   *         {@link EvictionAction} is performed.
   */
  public abstract int getMaximum();

  /** @return action that the {@link EvictionAlgorithm} takes when the maximum value is reached. */
  public abstract EvictionAction getAction();

  @Override
  public boolean equals(final Object obj) {
    if (obj == this) {
      return true;
    }
    if (!(obj instanceof EvictionAttributes)) {
      return false;
    }
    final EvictionAttributes other = (EvictionAttributes) obj;
    if (!getAlgorithm().equals(other.getAlgorithm())) {
      return false;
    }
    if (!getAction().equals(other.getAction())) {
      return false;
    }
    return getMaximum() == other.getMaximum();
  }

  @Override
  public int hashCode() {
    return getAlgorithm().hashCode() ^ getMaximum();
  }

  @Override
  public String toString() {
    final StringBuilder buffer = new StringBuilder(128);
    buffer.append(" algorithm=").append(getAlgorithm());
    if (!getAlgorithm().isNone()) {
      buffer.append("; action=").append(getAction());
      if (!getAlgorithm().isLRUHeap()) {
        buffer.append("; maximum=").append(getMaximum());
      }
      if (getObjectSizer() != null) {
        buffer.append("; sizer=").append(getObjectSizer());
      }
    }
    return buffer.toString();
  }

  /**
   * @param maximumEntries the number of entries to keep in the Region
   * @param evictionAction the action to perform when evicting an entry
   * @return an EvictionAttributes for the LIFOCapacityController
   * @since GemFire 5.7
   * @deprecated For internal use only.
   */
  @Deprecated
  public static EvictionAttributes createLIFOEntryAttributes(int maximumEntries,
      EvictionAction evictionAction) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LIFO_ENTRY)
        .setAction(evictionAction).setMaximum(maximumEntries);
  }

  /**
   * @param maximumMegabytes the maximum allowed bytes in the Region
   * @param evictionAction the action to perform when evicting an entry
   * @return an EvictionAttributes for the MemLIFOCapacityController
   * @since GemFire 5.7
   * @deprecated For internal use only.
   */
  @Deprecated
  public static EvictionAttributes createLIFOMemoryAttributes(int maximumMegabytes,
      EvictionAction evictionAction) {
    return new EvictionAttributesImpl().setAlgorithm(EvictionAlgorithm.LIFO_MEMORY)
        .setAction(evictionAction).setMaximum(maximumMegabytes).setObjectSizer(null);
  }

  public RegionAttributesType.EvictionAttributes convertToConfigEvictionAttributes() {
    RegionAttributesType.EvictionAttributes configAttributes =
        new RegionAttributesType.EvictionAttributes();
    EnumActionDestroyOverflow action = EnumActionDestroyOverflow.fromValue(getAction()
        .toString());
    EvictionAlgorithm algorithm = getAlgorithm();
    Optional<String> objectSizerClass = Optional.ofNullable(getObjectSizer())
        .map(c -> c.getClass().toString());
    String maximum = Integer.toString(getMaximum());

    if (algorithm.isLRUHeap()) {
      RegionAttributesType.EvictionAttributes.LruHeapPercentage heapPercentage =
          new RegionAttributesType.EvictionAttributes.LruHeapPercentage();
      heapPercentage.setAction(action);
      objectSizerClass.ifPresent(heapPercentage::setClassName);
      configAttributes.setLruHeapPercentage(heapPercentage);
    } else if (algorithm.isLRUMemory()) {
      RegionAttributesType.EvictionAttributes.LruMemorySize memorySize =
          new RegionAttributesType.EvictionAttributes.LruMemorySize();
      memorySize.setAction(action);
      objectSizerClass.ifPresent(memorySize::setClassName);
      memorySize.setMaximum(maximum);
      configAttributes.setLruMemorySize(memorySize);
    } else {
      RegionAttributesType.EvictionAttributes.LruEntryCount entryCount =
          new RegionAttributesType.EvictionAttributes.LruEntryCount();
      entryCount.setAction(action);
      entryCount.setMaximum(maximum);
      configAttributes.setLruEntryCount(entryCount);
    }

    return configAttributes;
  }

  public boolean isNoEviction() {
    return getAction() == EvictionAction.NONE;
  }

}
