001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.collections;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021/**
022 * Cache modes for {@link Cache} and related cache classes.
023 *
024 * <p>
025 * Defines how cache storage is implemented and when cached entries may be evicted.
026 *
027 * <h5 class='section'>See Also:</h5>
028 * <ul>
029 *    <li class='jc'>{@link Cache}
030 *    <li class='jc'>{@link Cache2}
031 *    <li class='jc'>{@link Cache3}
032 *    <li class='jc'>{@link Cache4}
033 *    <li class='jc'>{@link Cache5}
034 * </ul>
035 */
036public enum CacheMode {
037
038   /**
039    * No caching - all lookups invoke the supplier.
040    *
041    * <p>
042    * When this mode is used, the cache will not store any values. Every call to
043    * {@link Cache#get(Object)} or {@link Cache#get(Object, java.util.function.Supplier)}
044    * will invoke the supplier to compute the value.
045    *
046    * <p>
047    * This mode is useful for:
048    * <ul>
049    *    <li>Testing scenarios where you want fresh computation each time
050    *    <li>Development environments where caching might hide issues
051    *    <li>Temporarily disabling caching without code changes
052    * </ul>
053    */
054   NONE,
055
056   /**
057    * Weak caching - uses {@link java.util.WeakHashMap} for storage.
058    *
059    * <p>
060    * Cache entries can be garbage collected when keys are no longer strongly referenced elsewhere.
061    * The WeakHashMap is wrapped with {@link java.util.Collections#synchronizedMap(java.util.Map)}
062    * for thread safety.
063    *
064    * <p>
065    * This mode is useful for:
066    * <ul>
067    *    <li>Caching metadata about objects that may be unloaded (e.g., {@link Class} objects)
068    *    <li>Memory-sensitive applications where cache entries should not prevent garbage collection
069    *    <li>Scenarios where keys have limited lifetimes
070    * </ul>
071    *
072    * <p>
073    * <b>Note:</b> Weak caching comes with performance trade-offs:
074    * <ul>
075    *    <li>Slightly slower access due to synchronization overhead
076    *    <li>Entries may be removed unpredictably by the garbage collector
077    *    <li>Not suitable for high-concurrency scenarios
078    * </ul>
079    *
080    * <p>
081    * <b>Composite-key caches:</b> {@link Cache2}, {@link Cache3}, {@link Cache4}, and {@link Cache5} synthesize
082    * an internal composite-key object (e.g. a {@code TupleN}) on every lookup, and that object is never exposed
083    * to the caller - it is reachable only from the cache's own backing map. As a result, a WEAK-mode entry in
084    * one of these caches becomes GC-eligible <b>immediately</b> after insertion and may be reclaimed at the very
085    * next garbage collection, i.e. WEAK effectively behaves like {@link #NONE} once any GC has occurred. This is
086    * best-effort, <b>not retention-guaranteed</b> weak-key caching by design (not a bug) and is <i>not</i>
087    * equivalent to WEAK on the single-key {@link Cache}, where retention instead tracks the caller's own key and
088    * an entry survives for as long as that key remains strongly reachable elsewhere. If guaranteed retention is
089    * required, use {@link #FULL} (the default mode) instead of WEAK for the composite-key caches.
090    */
091   WEAK,
092
093   /**
094    * Full caching - uses {@link java.util.concurrent.ConcurrentHashMap} for storage.
095    *
096    * <p>
097    * Provides the best performance with lock-free reads and writes. Cached entries
098    * will remain in memory until explicitly removed or the cache is cleared due to
099    * exceeding the maximum size.
100    *
101    * <p>
102    * This is the default and recommended mode for most use cases, offering:
103    * <ul>
104    *    <li>Excellent performance with no synchronization overhead for reads
105    *    <li>Thread-safe concurrent access
106    *    <li>Predictable memory usage (entries stay until evicted)
107    *    <li>Suitable for high-concurrency scenarios
108    * </ul>
109    */
110   FULL;
111
112   // Constant values for parsing
113   private static final String CONST_NONE = "NONE";
114   private static final String CONST_WEAK = "WEAK";
115   private static final String CONST_FULL = "FULL";
116
117   /**
118    * Parses a string value into a {@link CacheMode}.
119    *
120    * <p>
121    * Performs case-insensitive matching against the enum constant names.
122    *
123    * <h5 class='section'>Examples:</h5>
124    * <p class='bjava'>
125    *    CacheMode.<jsm>parse</jsm>(<js>"none"</js>);  <jc>// Returns NONE</jc>
126    *    CacheMode.<jsm>parse</jsm>(<js>"WEAK"</js>);  <jc>// Returns WEAK</jc>
127    *    CacheMode.<jsm>parse</jsm>(<js>"Full"</js>);  <jc>// Returns FULL</jc>
128    *    CacheMode.<jsm>parse</jsm>(<jk>null</jk>);    <jc>// Returns FULL (default)</jc>
129    *    CacheMode.<jsm>parse</jsm>(<js>"invalid"</js>); <jc>// Returns FULL (default)</jc>
130    * </p>
131    *
132    * @param value The string value to parse. Can be <jk>null</jk>.
133    * @return The corresponding {@link CacheMode}, or {@link #FULL} if the value is <jk>null</jk> or invalid.
134    */
135   public static CacheMode parse(String value) {
136      if (value == null)
137         return FULL;
138      return switch (ucr(value)) {
139         case CONST_NONE -> NONE;
140         case CONST_WEAK -> WEAK;
141         case CONST_FULL -> FULL;
142         default -> FULL;
143      };
144   }
145}