/*
* Copyright 2004-2010 the Seasar Foundation and the Others.
*
* 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.slim3.memcache;
import java.util.Map;
import java.util.Set;
import org.slim3.util.ClassUtil;
import com.google.appengine.api.memcache.ErrorHandler;
import com.google.appengine.api.memcache.Expiration;
import com.google.appengine.api.memcache.InvalidValueException;
import com.google.appengine.api.memcache.Stats;
import com.google.appengine.api.memcache.MemcacheService.SetPolicy;
import com.google.apphosting.api.ApiProxy.CapabilityDisabledException;
/**
* A class to access memcache service.
*
* @author higa
* @since 1.0.0
*
*/
public final class Memcache {
private static Class<? extends MemcacheDelegate> delegateClass =
MemcacheDelegate.class;
/**
* Empties the cache of all values. Statistics are not affected. Note that
* clearAll() does not respect namespaces - this flushes the cache for every
* namespace.
*
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static void cleanAll() throws CapabilityDisabledException {
delegate().cleanAll();
}
/**
* Tests whether a given value is in cache, even if its value is null.
*
* @param key
* the key
* @return whether a given value is in cache
* @throws IllegalArgumentException
* if the key cannot be serialized
*/
public static boolean contains(Object key) throws IllegalArgumentException {
return delegate().contains(key);
}
/**
* Removes key from the cache.
*
* @param key
* the key
* @return true if an entry existed to delete
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static boolean delete(Object key) throws IllegalArgumentException,
CapabilityDisabledException {
return delegate().delete(key);
}
/**
* Removes the given key from the cache, and prevents it from being added
* under the MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT policy for
* millisNoReAdd milliseconds thereafter. Calls to a put(java.lang.Object,
* java.lang.Object, com.google.appengine.api.memcache.Expiration,
* com.google.appengine.api.memcache.MemcacheService.SetPolicy) method using
* MemcacheService.SetPolicy.SET_ALWAYS are not blocked, however.
*
* @param key
* the key
* @param millisNoReAdd
* the time during which calls to put using ADD_IF_NOT_PRESENT
* should be denied
* @return true if an entry existed to delete
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static boolean delete(Object key, long millisNoReAdd)
throws IllegalArgumentException, CapabilityDisabledException {
return delegate().delete(key, millisNoReAdd);
}
/**
* Removes keys from the cache.
*
* @param keys
* the keys for entries to delete.
* @return the Set of keys deleted. Any keys in keys but not in the returned
* set were not found in the cache.
* @throws NullPointerException
* the keys parameter is null
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*
*/
public static Set<Object> deleteAll(Iterable<?> keys)
throws NullPointerException, IllegalArgumentException,
CapabilityDisabledException {
return delegate().deleteAll(keys);
}
/**
* Removes keys from the cache.
*
* @param keys
* the keys for entries to delete.
* @param millisNoReAdd
* the time during which calls to put using ADD_IF_NOT_PRESENT
* should be denied
* @return the Set of keys deleted. Any keys in keys but not in the returned
* set were not found in the cache.
* @throws NullPointerException
* the keys parameter is null
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*
*/
public static Set<Object> deleteAll(Iterable<?> keys, long millisNoReAdd)
throws NullPointerException, IllegalArgumentException,
CapabilityDisabledException {
return delegate().deleteAll(keys, millisNoReAdd);
}
/**
* Returns a previously-stored value, or null if unset. Since null might be
* the set value in some cases, so we also have contains(Object) which
* returns boolean.
*
* @param <T>
* the return type
*
* @param key
* the key
* @return a previously-stored value
* @throws IllegalArgumentException
* if the key cannot be serialized
*/
@SuppressWarnings("unchecked")
public static <T> T get(Object key) throws IllegalArgumentException {
return (T) delegate().get(key);
}
/**
* Performs a get of multiple keys at once. This is more efficient than
* multiple separate calls to get(Object), and allows a single call to both
* test for contains(Object) and also fetch the value, because the return
* will not include mappings for keys not found.
*
* @param keys
* the keys.
* @return a mapping from keys to values of any entries found. If a
* requested key is not found in the cache, the key will not be in
* the returned Map.
* @throws NullPointerException
* if the keys parameter is null
* @throws IllegalArgumentException
* if the key cannot be serialized
*/
public static Map<Object, Object> getAll(Iterable<?> keys)
throws NullPointerException, IllegalArgumentException {
return delegate().getAll(keys);
}
/**
* Atomically fetches, increments, and stores a given integral value.
* "Integral" types are Byte, Short, Integer, Long, and in some cases String
* (if the string is parseable as a number, for example via
* Long.parseLong(String). The entry must already exist, and have a
* non-negative value.
*
* Incrementing by positive amounts will reach signed 64-bit max (2^63 - 1)
* and then wrap-around to signed 64-bit min (-2^63), continuing increments
* from that point.
*
* To facilitate use as an atomic countdown, incrementing by a negative
* value (i.e. decrementing) will not go below zero: incrementing 2 by -5
* will return 0, not -3. However, due to the way numbers are stored,
* decrementing -3 by -5 will result in -8; so the zero-floor rule only
* applies to decrementing numbers that were positive.
*
* Note: The actual representation of all numbers in Memcache is a string.
* This means if you initially stored a number as a string (e.g., "10") and
* then increment it, everything will work properly, including wrapping
* beyond signed 64-bit int max. However, if you get the key past the point
* of wrapping, you will receive an unsigned integer value, not a signed
* integer value.
*
* @param key
* the key
* @param delta
* the size of the increment, positive or negative.
* @return the post-increment value, as a long. However, a get(Object) of
* the key will still have the original type (Byte, Short, etc.). If
* there is no entry for key, returns null.
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws InvalidValueException
* if the object incremented is not of a integral type
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static Long increment(Object key, long delta)
throws IllegalArgumentException, InvalidValueException,
CapabilityDisabledException {
return delegate().increment(key, delta);
}
/**
* Like normal increment, but allows for an optional initial value for the
* key to take on if not already present in the cache.
*
* @param key
* the key
* @param delta
* the size of the increment, positive or negative.
* @param initialValue
* the value to insert into the cache if the key is not present
* @return the post-increment value, as a long. However, a get(Object) of
* the key will still have the original type (Byte, Short, etc.). If
* there is no entry for key, returns null.
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws InvalidValueException
* if the object incremented is not of a integral type
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static Long increment(Object key, long delta, long initialValue)
throws IllegalArgumentException, InvalidValueException,
CapabilityDisabledException {
return delegate().increment(key, delta, initialValue);
}
/**
* Like normal increment, but increments a batch of separate keys in
* parallel by the same delta.
*
* @param keys
* the keys
* @param delta
* the size of the increment, positive or negative.
* @return mapping keys to their new values; values will be null if they
* could not be incremented or were not present in the cache
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static Map<Object, Long> incrementAll(Iterable<?> keys, long delta)
throws IllegalArgumentException, CapabilityDisabledException {
return delegate().incrementAll(keys, delta);
}
/**
* Like normal increment, but increments a batch of separate keys in
* parallel by the same delta and potentially sets a starting value.
*
* @param keys
* the keys
* @param delta
* the size of the increment, positive or negative.
* @param initialValue
* the value to insert into the cache if the key is not present
* @return mapping keys to their new values; values will be null if they
* could not be incremented for whatever reason
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static Map<Object, Long> incrementAll(Iterable<?> keys, long delta,
long initialValue) throws IllegalArgumentException,
CapabilityDisabledException {
return delegate().incrementAll(keys, delta, initialValue);
}
/**
* Like normal increment, but accepts a mapping of separate controllable
* offsets for each key individually.
*
* @param offsets
* the offsets
*
* @return mapping keys to their new values; values will be null if they
* could not be incremented for whatever reason
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static Map<Object, Long> incrementAll(Map<Object, Long> offsets)
throws IllegalArgumentException, CapabilityDisabledException {
return delegate().incrementAll(offsets);
}
/**
* Like normal increment, but accepts a mapping of separate controllable
* offsets for each key individually. Callers may also pass an initial value
* for the keys to take on if they are not already present in the cache.
*
* @param offsets
* the offsets
* @param initialValue
* the value to insert into the cache if the key is not present
* @return mapping keys to their new values; values will be null if they
* could not be incremented for whatever reason
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static Map<Object, Long> incrementAll(Map<Object, Long> offsets,
long initialValue) throws IllegalArgumentException,
CapabilityDisabledException {
return delegate().incrementAll(offsets, initialValue);
}
/**
* A convenience shortcut, equivalent to put(key, value, null,
* SetPolicy.SET_ALWAYS).
*
* @param key
* the key
* @param value
* the value
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static void put(Object key, Object value)
throws IllegalArgumentException, CapabilityDisabledException {
delegate().put(key, value);
}
/**
* A convenience shortcut, equivalent to put(key, value, expires,
* SetPolicy.SET_ALWAYS).
*
* @param key
* the key
* @param value
* the value
* @param expires
* expiration time for the new values, or null for no time-based
* expiration
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static void put(Object key, Object value, Expiration expires)
throws IllegalArgumentException, CapabilityDisabledException {
delegate().put(key, value, expires);
}
/**
* Store a new value into the cache, using key, but subject to the policy
* regarding existing entries.
*
* @param key
* the key
* @param value
* the value
* @param expires
* expiration time for the new values, or null for no time-based
* expiration
* @param policy
* Requests particular handling regarding pre-existing entries
* under the same key. This parameter must not be null.
* @return true if a new entry was created, false if not because of the
* policy.
* @throws NullPointerException
* if the policy parameter is null
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static boolean put(Object key, Object value, Expiration expires,
SetPolicy policy) throws NullPointerException,
IllegalArgumentException, CapabilityDisabledException {
return delegate().put(key, value, expires, policy);
}
/**
* A convenience shortcut, equivalent to putAll(values, null,
* SetPolicy.SET_ALWAYS).
*
* @param values
* key/value mappings for new entries to add to the cache
* @throws NullPointerException
* if the values parameter is null
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static void putAll(Map<Object, Object> values)
throws NullPointerException, IllegalArgumentException,
CapabilityDisabledException {
delegate().putAll(values);
}
/**
* A convenience shortcut, equivalent to putAll(values, expires,
* SetPolicy.SET_ALWAYS).
*
* @param values
* key/value mappings for new entries to add to the cache
* @param expires
* expiration time for the new values, or null for no time-based
* expiration
* @throws NullPointerException
* if the values parameter is null
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static void putAll(Map<Object, Object> values, Expiration expires)
throws NullPointerException, IllegalArgumentException,
CapabilityDisabledException {
delegate().putAll(values, expires);
}
/**
* A batch-processing variant of put(java.lang.Object, java.lang.Object,
* com.google.appengine.api.memcache.Expiration,
* com.google.appengine.api.memcache.MemcacheService.SetPolicy). This is
* more efficiently implemented by the service than multiple calls.
*
* @param values
* key/value mappings for new entries to add to the cache
* @param expires
* expiration time for the new values, or null for no time-based
* expiration
* @param policy
* what to do if the entry is or is not already present
* @return the set of keys for which entries were created. Keys in values
* may not be in the returned set because of the policy regarding
* pre-existing entries.
* @throws NullPointerException
* if the values parameter is null or if the policy parameter is
* null
* @throws IllegalArgumentException
* if the key cannot be serialized
* @throws CapabilityDisabledException
* if App Engine is read only
*/
public static Set<Object> putAll(Map<Object, Object> values,
Expiration expires, SetPolicy policy) throws NullPointerException,
IllegalArgumentException, CapabilityDisabledException {
return delegate().putAll(values, expires, policy);
}
/**
* Sets the current error handler.
*
* @param errorHandler
* the error handler
* @return {@link MemcacheDelegate}
* @throws NullPointerException
* if the errorHandler parameter is null
*/
public static MemcacheDelegate errorHandler(ErrorHandler errorHandler)
throws NullPointerException {
return delegate().errorHandler(errorHandler);
}
/**
* Returns some statistics about the cache and its usage. Note that
* statistics() does not respect namespaces - this will return stats for
* every namespace. The response will never be null.
*
* @return some statistics
*/
public static Stats statistics() {
return delegate().statistics();
}
/**
* Returns the delegate class.
*
* @return the delegate class
*/
public static Class<? extends MemcacheDelegate> delegateClass() {
return delegateClass;
}
/**
* Sets the delegate class and returns the old one.
*
* @param clazz
* the delegate class
* @return the old delegate class
* @throws NullPointerException
* if the clazz parameter is null
*/
public static Class<? extends MemcacheDelegate> delegateClass(
Class<? extends MemcacheDelegate> clazz)
throws NullPointerException {
if (clazz == null) {
throw new NullPointerException(
"The clazz parameter must not be null.");
}
Class<? extends MemcacheDelegate> old = delegateClass;
delegateClass = clazz;
return old;
}
/**
* Creates a {@link MemcacheDelegate}.
*
* @return a {@link MemcacheDelegate}
*/
protected static MemcacheDelegate delegate() {
return ClassUtil.newInstance(delegateClass);
}
private Memcache() {
}
}