org.cp.elements.data.caching.AbstractCache Maven / Gradle / Ivy
/*
* Copyright 2011-Present Author or Authors.
*
* 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 org.cp.elements.data.caching;
import static org.cp.elements.lang.RuntimeExceptionsFactory.newUnsupportedOperationException;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import org.cp.elements.lang.ObjectUtils;
import org.cp.elements.lang.annotation.NotNull;
import org.cp.elements.lang.annotation.Nullable;
import org.cp.elements.util.CollectionUtils;
/**
* Abstract base class supporting the implementation of different types of {@link Cache Caches}.
*
* @author John Blum
* @param {@link Class type} of the {@link Cache} key.
* @param {@link Class type} of the {@link Cache} value.
* @see org.cp.elements.data.caching.Cache
* @see java.lang.Comparable
* @since 1.0.0
*/
public abstract class AbstractCache, VALUE> implements Cache {
private volatile Object lock;
private volatile String name;
/**
* Gets the configured {@link Object lock} used to run operations on this {@link Cache} atomically / synchronously.
*
* If no {@link Object lock} has been configured, that is, the {@link Object lock} is {@literal null},
* then the {@link Cache} operations will not be atomic.
*
* No {@link Object lock} is configured by default.
*
* @return the configured {@link Object lock}; may be {@literal null}.
*/
@Override
public @Nullable Object getLock() {
return this.lock;
}
/**
* Configures the {@link Object lock} to synchronize the operation on this {@link Cache} so they execute atomically.
*
* @param lock {@link Object} to use as a {@literal lock} to synchronize operations on this {@link Cache}.
* @see #getLock()
*/
public void setLock(@Nullable Object lock) {
this.lock = lock;
}
/**
* Clears the entire contents of (all entries from) this {@link Cache}.
*
* This {@link Cache} operation is not supported by default since it can be a very costly operation,
* especially in a distributed context. Caching providers and implementors should therefore provide
* a custom and efficient implementation to clear the contents and {@link Cache.Entry entries} from
* this {@link Cache}, which is likely to be data store dependent.
*
* @throws UnsupportedOperationException by default.
*/
@Override
public void clear() {
throw new UnsupportedOperationException("Clear is not supported");
}
/**
* Removes the {@link Cache.Entry entry} mapped to the given {@link KEY key} in this {@link Cache}.
*
* @param key {@link KEY key} identifying the entry to remove (evict) from this {@link Cache}.
* @throws UnsupportedOperationException by default.
*/
@Override
public void evict(KEY key) {
throw newUnsupportedOperationException("Eviction is not supported");
}
/**
* Gets the {@link VALUE value} stored in this {@link Cache} mapped to the given {@link KEY}.
*
* Returns {@literal null} if the {@link VALUE value} mapped to the given {@link KEY key} is {@literal null},
* or this {@link Cache} does not contain an entry mapped to the given {@link KEY key}.
*
* @param key {@link KEY key} mapped to the {@link VALUE value} returned.
* @return the {@link VALUE value} mapped to the given {@link KEY key}, or return {@literal null}
* if an {@link Cache.Entry entry} with the given {@link KEY key} does not exist,
* or a {@link VALUE value} for the given {@link KEY key} is {@literal null}.
* @throws UnsupportedOperationException by default.
* @see #put(Comparable, Object)
*/
@Override
public VALUE get(KEY key) {
throw newUnsupportedOperationException("Get is not supported");
}
/**
* Returns the {@link String name} of this {@link Cache}.
*
* The configured {@link String name} may be {@literal null}.
*
* @return the {@link String name} of this {@link Cache}; may be {@literal null}.
* @see #named(String)
*/
@Override
public @Nullable String getName() {
return this.name;
}
/**
* Returns an {@link Iterator} iterating over the {@link Cache.Entry entries} in this {@link Cache}.
*
* When extending from {@link AbstractCache}, caching providers must be careful to either override
* the {@link #keys()} or this {@literal iterator} method, since {@literal iterator()} calls {@link #keys()}
* and {@link #keys()} calls {@literal iterator()}, which will end up in infinite recursion.
*
* @return an {@link Iterator} iterating over the {@link Cache.Entry entries} in this {@link Cache}.
* @see org.cp.elements.data.caching.AbstractCache.AttachedCacheEntry
* @see org.cp.elements.data.caching.Cache.Entry
* @see java.util.Iterator
* @see #keys()
*/
@Override
public Iterator> iterator() {
return new Iterator>() {
private final Iterator keys = CollectionUtils.nullSafeSet(keys()).iterator();
@Override
public boolean hasNext() {
return this.keys.hasNext();
}
@Override
public Entry next() {
return AttachedCacheEntry.from(AbstractCache.this, this.keys.next());
}
};
}
/**
* Returns all {@link KEY keys} in this {@link Cache}.
*
* Returns an {@link Collections#emptySet()} by default.
*
* @return a {@link Set} containing all the {@link KEY keys} from this {@link Cache}.
* Returns an {@link Set#isEmpty() empty Set} if there are no {@link Cache.Entry entries}
* in this {@link Cache}.
* @see java.util.Set
* @see #iterator()
*/
@Override
public Set keys() {
return Collections.emptySet();
}
/**
* Puts the {@link VALUE value} in this {@link Cache} mapped to the given {@link KEY key}.
*
* @param key {@link KEY} mapped to the {@link VALUE value}; must not be {@literal null}.
* @param value {@link VALUE} put in this {@link Cache} mapped to the {@link KEY key}.
* @throws IllegalArgumentException if the {@link KEY key} is {@literal null}.
* @throws UnsupportedOperationException by default.
* @see #get(Comparable)
*/
@Override
public void put(KEY key, VALUE value) {
throw newUnsupportedOperationException("Put is not supported");
}
/**
* Builder method to set (configure) the {@link String name} of this {@link Cache}.
*
* @param {@link Class type} of this {@link Cache}.
* @param name {@link String} containing the {@literal name} to assign to this {@link Cache}.
* @return this {@link Cache}.
*/
@SuppressWarnings("unchecked")
public @NotNull > T named(@Nullable String name) {
this.name = name;
return (T) this;
}
/**
* Abstract base class encapsulating functionality common to all {@link Cache.Entry} implementations.
*
* @param {@link Class type} of the {@link Cache.Entry} key.
* @param {@link Class type} of the {@link Cache.Entry} value.
* @see org.cp.elements.data.caching.Cache.Entry
* @see java.lang.Comparable
*/
protected abstract static class AbstractEntry, VALUE> implements Cache.Entry {
private final Cache cache;
private final KEY key;
/**
* Constructs a new instance of {@link AbstractEntry} initialized with the given, required {@link Cache}
* used as the {@literal source} of this {@link Cache.Entry} along with the given, required {@link KEY key}.
*
* @param cache {@link Cache} used as the {@literal source} of this {@link Cache.Entry};
* must not be {@literal null}.
* @param key {@link KEY key} in the {@link Cache.Entry} mapping; must not be {@literal null}.
* @throws IllegalArgumentException if the {@link Cache} or the {@link KEY key} is {@literal null}.
* @see org.cp.elements.data.caching.Cache
*/
protected AbstractEntry(@NotNull Cache cache, @NotNull KEY key) {
this.cache = ObjectUtils.requireObject(cache, "Cache used as the source of this Entry is required");
this.key = ObjectUtils.requireObject(key, "Key is required");
}
@Override
public @NotNull Cache getSource() {
return this.cache;
}
@Override
public @NotNull KEY getKey() {
return this.key;
}
}
/**
* Abstract Data Type (ADT) modeling an {@literal attached} {@link Cache.Entry}, which is backed by
* the underlying {@link Cache} reflecting changes to the {@link Cache} in realtime.
*
* @param {@link Class type} of the {@link Cache.Entry} key.
* @param {@link Class type} of the {@link Cache.Entry} value.
* @see org.cp.elements.data.caching.AbstractCache.AbstractEntry
* @see java.lang.Comparable
*/
@SuppressWarnings("unused")
public static class AttachedCacheEntry, VALUE> extends AbstractEntry {
/**
* Factory method used to construct a new instance of {@link AttachedCacheEntry} initialized with the given,
* required {@link Cache} used as the {@literal source} of this {@link Cache.Entry} along with the given,
* required {@link KEY key}.
*
* @param {@link Class type} of the {@link Cache.Entry} key.
* @param {@link Class type} of the {@link Cache.Entry} value.
* @param cache {@link Cache} used as the {@literal source} of this {@link Cache.Entry};
* must not be {@literal null}.
* @param key {@link KEY key} in the {@link Cache.Entry} mapping; must not be {@literal null}.
* @return a new {@link AttachedCacheEntry}.
* @throws IllegalArgumentException if the {@link Cache} or the {@link KEY key} is {@literal null}.
* @see org.cp.elements.data.caching.Cache
* @see java.lang.Comparable
*/
public static @NotNull , VALUE> AttachedCacheEntry from(
@NotNull Cache cache, @NotNull KEY key) {
return new AttachedCacheEntry<>(cache, key);
}
/**
* Constructs a new instance of {@link AttachedCacheEntry} initialized with the given, required {@link Cache}
* used as the {@literal source} of this {@link Cache.Entry} along with the given, required {@link KEY key}.
*
* @param cache {@link Cache} used as the {@literal source} of this {@link Cache.Entry};
* must not be {@literal null}.
* @param key {@link KEY key} in the {@link Cache.Entry} mapping; must not be {@literal null}.
* @throws IllegalArgumentException if the {@link Cache} or the {@link KEY key} is {@literal null}.
* @see org.cp.elements.data.caching.Cache
*/
protected AttachedCacheEntry(@NotNull Cache cache, @NotNull KEY key) {
super(cache, key);
}
}
/**
* Abstract Data Type (ADT) modeling a simple, {@literal detached} {@link Cache.Entry}, that is not associated
* with or backed by any {@link Cache}.
*
* @param {@link Class type} of the {@link Cache.Entry} key.
* @param {@link Class type} of the {@link Cache.Entry} value.
* @see org.cp.elements.data.caching.Cache.Entry
* @see java.lang.Comparable
*/
@SuppressWarnings("unused")
public static class SimpleCacheEntry, VALUE> implements Cache.Entry {
/**
* Factory method used to construct a new instance of {@link SimpleCacheEntry} initialized with the given,
* required {@link KEY key} and {@link VALUE value}.
*
* @param {@link Class type} of the {@link Cache.Entry} key.
* @param {@link Class type} of the {@link Cache.Entry} value.
* @param key {@link KEY key} in this {@link Cache.Entry} mapping; must not be {@literal null}.
* @param value {@link VALUE} mapped to the {@link KEY key} in this {@link Cache.Entry} mapping.
* @return a new {@link SimpleCacheEntry}.
* @throws IllegalArgumentException if the {@link KEY key} is {@literal null}.
* @see java.lang.Comparable
*/
public static @NotNull , VALUE> SimpleCacheEntry of(
@NotNull KEY key, @Nullable VALUE value) {
return new SimpleCacheEntry<>(key, value);
}
private final KEY key;
private final VALUE value;
/**
* Constructs a new instance of {@link SimpleCacheEntry} initialized with the given, required {@link KEY key}
* and {@link VALUE value}.
*
* @param key {@link KEY key} in this {@link Cache.Entry} mapping; must not be {@literal null}.
* @param value {@link VALUE} mapped to the {@link KEY key} in this {@link Cache.Entry} mapping.
* @throws IllegalArgumentException if the {@link KEY key} is {@literal null}.
*/
public SimpleCacheEntry(@NotNull KEY key, @Nullable VALUE value) {
this.key = ObjectUtils.requireObject(key, "Key is required");
this.value = value;
}
@Override
public @NotNull KEY getKey() {
return this.key;
}
@Override
public @Nullable Cache getSource() {
return null;
}
@Override
public @Nullable VALUE getValue() {
return this.value;
}
@Override
public void setValue(VALUE value) {
throw newUnsupportedOperationException("Value of Cache.Entry(%s) cannot be set", getKey());
}
@Override
public @NotNull Entry materialize() {
return this;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy