package com.googlecode.objectify.cache; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.KeyFactory; import com.google.appengine.api.memcache.MemcacheService; import com.google.appengine.api.memcache.MemcacheService.CasValues; import com.google.appengine.api.memcache.MemcacheService.IdentifiableValue; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; /** * Subset of MemcacheService used by EntityMemcache, but smart enough to translate Key into the stringified * version so that the memcache keys are intelligible. Also guards against calling through to the underlying * service when the operation is a no-op (ie, the collection of keys to operate on is empty). * * @author Jeff Schnitzer <jeff@infohazard.org> */ public class KeyMemcacheService { /** */ private static final Function<Key, String> STRINGIFY = new Function<Key, String>() { @Override public String apply(Key input) { return KeyFactory.keyToString(input); } }; /** */ MemcacheService service; /** */ public KeyMemcacheService(MemcacheService service) { this.service = service; } private <T> Map<Key, T> keyify(Map<String, T> stringified) { Map<Key, T> result = Maps.newLinkedHashMap(); for (Map.Entry<String, T> entry: stringified.entrySet()) result.put(KeyFactory.stringToKey(entry.getKey()), entry.getValue()); return result; } private Set<Key> keyify(Set<String> stringified) { Set<Key> result = Sets.newLinkedHashSet(); for (String str: stringified) result.add(KeyFactory.stringToKey(str)); return result; } private <T> Map<String, T> stringify(Map<Key, T> keyified) { Map<String, T> result = Maps.newLinkedHashMap(); for (Map.Entry<Key, T> entry: keyified.entrySet()) result.put(KeyFactory.keyToString(entry.getKey()), entry.getValue()); return result; } private Collection<String> stringify(Collection<Key> keys) { return Collections2.transform(keys, STRINGIFY); } public Map<Key, IdentifiableValue> getIdentifiables(Collection<Key> keys) { if (keys.isEmpty()) return Collections.emptyMap(); Map<String, IdentifiableValue> map = service.getIdentifiables(stringify(keys)); return keyify(map); } public Map<Key, Object> getAll(Collection<Key> keys) { if (keys.isEmpty()) return Collections.emptyMap(); Map<String, Object> map = service.getAll(stringify(keys)); return keyify(map); } public void putAll(Map<Key, Object> map) { if (map.isEmpty()) return; service.putAll(stringify(map)); } public Set<Key> putIfUntouched(Map<Key, CasValues> map) { if (map.isEmpty()) return Collections.emptySet(); Set<String> result = service.putIfUntouched(stringify(map)); return keyify(result); } public void deleteAll(Collection<Key> keys) { if (keys.isEmpty()) return; service.deleteAll(stringify(keys)); } @SuppressWarnings("deprecation") public void setErrorHandler(com.google.appengine.api.memcache.ErrorHandler handler) { service.setErrorHandler(handler); } }