package org.cache2k.expiry;

/*
 * #%L
 * cache2k API
 * %%
 * Copyright (C) 2000 - 2016 headissue GmbH, Munich
 * %%
 * 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.
 * #L%
 */

import org.cache2k.Cache2kBuilder;
import org.cache2k.CacheEntry;

import java.util.concurrent.TimeUnit;

/**
 * A custom policy which allows to calculate a dynamic expiry time for an entry after an
 * insert or update.
 *
 * <p>For some expiry calculations it is useful to know the previous entry, e.g. to detect
 * whether the stored data was updated. If a previous value is present in the cache,
 * it is passed to this method. Expired old entries will be passed in also, if still present
 * in the cache.
 *
 * @author Jens Wilke; created: 2014-10-14
 * @since 0.20
 */
public interface ExpiryPolicy<K, V> extends ExpiryTimeValues {

  /**
   * Returns the time of expiry in milliseconds since epoch.
   *
   * <p>By default expiry itself happens lenient, zero or some milliseconds after
   * the returned value. If sharp expiry is requested, the value will not be
   * returned any more by the cache when the point in time is reached.
   * The cache parameters {@link Cache2kBuilder#sharpExpiry(boolean)}
   * and {@link Cache2kBuilder#refreshAhead(boolean)} influence the behaviour.
   *
   * <p><b>Inserts or updates:</b> It is possible to return different expiry times for
   * inserts or updates. An update can be detected by the presence of the old entry.
   *
   * <p><b>Calling cache operations:</b> It is illegal to call any
   * cache methods from this method. The outcome is undefined and it can
   * cause a deadlock.
   *
   * <p><b>null values:</b> If the loader returns a {@code null} value, the expiry
   * policy will be called, regardless of the {@link Cache2kBuilder#permitNullValues} setting.
   * If the expiry policy returns a {@link #NO_CACHE} the entry will be removed. If the expiry
   * policy returns a different time value, a {@code NullPointerException} will be propagated
   * if {@code null} values are not permitted.
   *
   * <p><b>API rationale:</b> The recently loaded or inserted data is not passed in via a cache
   * entry object. Using a cache entry is desirable for API design reasons to have a thinner interface.
   * But the "real" entry can only be filled after the expiry policy is done, passing in an entry object
   * would mean to build a temporary object. Second, the properties that are needed by the implementation
   * are available directly. OTOH, 4-arity breaks Java 8 lambdas.
   *
   * @param key the cache key used for inserting or loading
   * @param value the value to be cached. May be null if the loader returns null, regardless of the
   *               {@link Cache2kBuilder#permitNullValues} setting.
   * @param loadTime The time the entry was inserted or loaded. If a loader was used,
   *                 this is the time before the loader was called.
   * @param oldEntry entry representing the current mapping, if there is a value present.
   *                  If the old entry holds an exception, this is null. Expired entries will be
   *                 passed in as well if still in the cache.
   * @return time the time of expiry in millis since epoch. {@link #NO_CACHE} if it should not cached.
   *         If {@link Cache2kBuilder#refreshAhead} is enabled the return value {@link #NO_CACHE} will remove
   *         the entry from the cache and trigger an immediate refresh. The return value {@link #ETERNAL} means
   *         that there is no specific expiry time known or needed. The effective expiry duration will never
   *         be longer than the configured expiry value via {@link Cache2kBuilder#expireAfterWrite(long, TimeUnit)}.
   *         If a negative value is returned, the negated value will be the expiry time
   *         used, but sharp expiry is requested. See {@link Cache2kBuilder#sharpExpiry(boolean)}.
   *
   * @see ValueWithExpiryTime#getCacheExpiryTime()
   */
  long calculateExpiryTime(
      K key,
      V value,
      long loadTime,
      CacheEntry<K, V> oldEntry);

}

@@ -1770,21 +1770,203 @@
 aviour.%0A
+   * It is also possible to request a sharp timeout for some entries. This is done%0A   * by returning a negative time value, see the further comments for the return%0A   * value below.%0A
    *%0A
-
    * %3Cp%3E
@@ -2298,24 +2298,243 @@
 dlock.%0A   *%0A
+   * %3Cp%3E%3Cb%3ECalling time:%3C/b%3E%3C/p%3EThe method is called from the cache, whenever a%0A   * cache entry is updated. However, it is legal that the cache calls the%0A   * method at arbitrary times during the entry lifecycle.%0A   *%0A
    * %3Cp%3E%3Cb%3En
@@ -3288,16 +3288,36 @@
 y object
+, increasing GC load
 . Second
@@ -3341,16 +3341,21 @@
 that are
+%0A   *
  needed 
@@ -3375,21 +3375,16 @@
 entation
-%0A   *
  are ava
@@ -3399,16 +3399,30 @@
 irectly.
+ The downside,
  OTOH, 4
@@ -4776,19 +4776,106 @@
 uested. 
-See
+Use %7B@link Expiry#toSharpTime(long)%7D to have a more%0A   *         expressive code. See also
  %7B@link 

improve epxiry policy doc