Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.tectonica.gae;
  
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
 
 
 import  com.google.appengine.api.NamespaceManager;
 import  com.google.appengine.api.datastore.Blob;
 import  com.google.appengine.api.datastore.DatastoreService;
 import  com.google.appengine.api.datastore.DatastoreServiceFactory;
 import  com.google.appengine.api.datastore.Entity;
 import  com.google.appengine.api.datastore.EntityNotFoundException;
 import  com.google.appengine.api.datastore.Key;
 import  com.google.appengine.api.datastore.KeyFactory;
 import  com.google.appengine.api.datastore.Query;
 import  com.google.appengine.api.datastore.Query.Filter;
 import  com.google.appengine.api.datastore.Query.FilterOperator;
 import  com.google.appengine.api.datastore.Query.FilterPredicate;
 import  com.google.appengine.api.memcache.MemcacheService;
 import  com.google.appengine.api.memcache.MemcacheServiceFactory;
 
 public class GaeKeyValueStore<V extends Serializableextends KeyValueStore<String, V>
 {
 	private final DatastoreService ds;
 
 	private final Class<V> valueClass;
 	private final String namespace;
 	private final String kind;
 	private final Key ancestor// dummy parent for all entities to guarantee Datastore consistency
 	private final Serializer<V> serializer;
 	private final List<GaeIndexImpl<?>> indexes;
 
 	public GaeKeyValueStore(Class<V> valueClassKeyMapper<String, V> keyMapper)
 	{
 		this(valueClassnullkeyMappernull);
 	}
 
 	public GaeKeyValueStore(Class<V> valueClassString namespaceKeyMapper<String, V> keyMapper)
 	{
 		this(valueClassnamespacekeyMappernull);
 	}
 
 	public GaeKeyValueStore(Class<V> valueClassString namespaceKeyMapper<String, V> keyMapperSerializer<V> serializer)
 	{
 		super(keyMapper);
 		if (valueClass == null)
 			throw new NullPointerException("valueClass");
 		if (serializer == null)
 			serializer = new JavaSerializer<V>();
 		this. = namespace;
 		NamespaceManager.set(namespace);
 		this. = DatastoreServiceFactory.getDatastoreService();
 		this. = valueClass;
 		this. = valueClass.getSimpleName();
 		this. = KeyFactory.createKey();
 		this. = new ArrayList<>();
 		this. = serializer;
 
 		// create cache now that all values (specifically 'kind') are initialized
 		super.initializeCache();
 	}
 
 	protected void initializeCache()
 	{
 		// prevent execution of the parent's attempt to create cache, we'll call it manually when we're ready
 	}
 
 	protected Cache<String, V> createCache()
 	{
 		// we're returning a memcached-based wrapper here, so the 'kind' property needs to be set
 		if ( instanceof JavaSerializer)
 			return new JavaSerializeCache();
 		return new CustomSerializeCache();
 	}
 
 	private Key keyOf(String key)
 	{
 		NamespaceManager.set();
 		return KeyFactory.createKey(key);
 	}

GETTERS /
 
 
	protected V dbGet(String key)
	{
		try
		{
			return entityToValue(.get(keyOf(key)));
		}
		catch (EntityNotFoundException e)
		{
			return null;
		}
	}
	{
		return entryIteratorOfQuery(newQuery()); // query without filters = all
	}
	{
		return keyIteratorOfQuery(newQuery().setKeysOnly());
	}
	public Iterator<V> valueIterator()
	{
	}
	{
		if (keys.size() > 30)
			throw new RuntimeException("GAE doesn't support more than 30 at the time, need to break it");
		List<Key> gaeKeys = new ArrayList<>(keys.size());
		for (String key : keys)
			gaeKeys.add(keyOf(key));
		// we define a filter based on the IN operator, which returns values in the order of listing.
		// see: https://cloud.google.com/appengine/docs/java/datastore/queries#Java_Query_structure
		Filter filter = new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.IN, gaeKeys);
		return entryIteratorOfQuery(newQuery().setFilter(filter));
	}

SETTERS (UTILS) /
	protected Modifier<String, V> getModifier(final String keyModificationType purpose)
	{
		// insert, replace and update are all treated the same in GAE: all simply do save()
		return new Modifier<String, V>()
		{
			public V getModifiableValue()
			{
				// we use here same calls as if for read-only value, because in both cases a new instance is deserialized
				// NOTE: if we ever switch to a different implementation, with local objects, this wouldn't work
				return get(keyfalse);
			}
			public void dbPut(V value)
			{
				save(keyvalue);
			}
		};
	}
	{
		return GaeMemcacheLock.getLock( + ":" + keytrue);
	}

SETTERS /
	protected void dbInsert(String key, V value)
	{
		save(keyvalue);
	}

DELETERS /
	protected boolean dbDelete(String key)
	{
		.delete(keyOf(key));
		return true// we don't really know if the key previously existed
	}
	protected int dbDeleteAll()
	{
		int removed = 0;
		for (Entity entity : .prepare(newQuery().setKeysOnly()).asIterable())
		{
			.delete(entity.getKey());
			removed++;
		}
		return removed// an estimate. we have to assume that all keys existed before delete
	}

INDEXES /
	public <F> Index<String, V, F> createIndex(String indexNameIndexMapper<V, F> mapFunc)
	{
		GaeIndexImpl<F> index = new GaeIndexImpl<>(mapFuncindexName);
		.add(index);
		return index;
	}

GAE implementation of an index - simply exposes the Datastore property filters

Author(s):
Zach Melamed
	private class GaeIndexImpl<F> extends Index<String, V, F>
	{
		public GaeIndexImpl(IndexMapper<V, F> mapFuncString name)
		{
			super(mapFuncname);
		}
		public Iterator<KeyValue<String, V>> iteratorOf(F f)
		{
		}
		{
			return keyIteratorOfQuery(newIndexQuery(f).setKeysOnly());
		}
		public Iterator<V> valueIteratorOf(F f)
		{
		}
		private Query newIndexQuery(F f)
		{
			Filter filter = new FilterPredicate(propertyName(), FilterOperator.EQUAL, f);
			return newQuery().setFilter(filter);
		}
		private String propertyName()
		{
		}
		private F getIndexedFieldOf(V value)
		{
			return .getIndexedFieldOf(value);
		}
	}

DATASTORE UTILS /
	private static final String COL_NAME_ENTRY_VALUE = "value";
	private static final String COL_NAME_INDEX_PREFIX = "_i_";
	private static final String BOGUS_ANCESTOR_KEY_NAME = " ";
	private V entityToValue(Entity entity)
	{
		Blob blob = (Blob) entity.getProperty();
		return .bytesToObj(blob.getBytes(), );
	}
	private Entity entryToEntity(String key, V value)
	{
		Entity entity = new Entity(key);
		entity.setProperty(new Blob(.objToBytes(value)));
		for (GaeIndexImpl<?> index : )
		{
			Object field = (value == null) ? null : index.getIndexedFieldOf(value);
			entity.setProperty(index.propertyName(), field);
		}
		return entity;
	}
	private void save(String key, V value)
	{
		.put(entryToEntity(keyvalue));
	}
	private Query newQuery()
	{
		NamespaceManager.set();
		return new Query().setAncestor();
	}
	private Iterator<KeyValue<String, V>> entryIteratorOfQuery(Query q)
	{
		final Iterator<Entity> iter = .prepare(q).asIterator();
		return new Iterator<KeyValue<String, V>>()
		{
			public boolean hasNext()
			{
				return iter.hasNext();
			}
			public KeyValue<String, V> next()
			{
				final Entity entity = iter.next();
				return new KeyValue<String, V>()
				{
					public String getKey()
					{
						return entity.getKey().getName();
					}
					public V getValue()
					{
						return entityToValue(entity);
					}
				};
			}
			public void remove()
			{
			}
		};
	}
	private Iterator<StringkeyIteratorOfQuery(Query q)
	{
		final Iterator<Entity> iter = .prepare(q).asIterator();
		return new Iterator<String>()
		{
			public boolean hasNext()
			{
				return iter.hasNext();
			}
			public String next()
			{
				return iter.next().getKey().getName();
			}
			public void remove()
			{
			}
		};
	}
	private Iterator<V> valueIteratorOfQuery(Query q)
	{
		final Iterator<Entity> iter = .prepare(q).asIterator();
		return new Iterator<V>()
		{
			public boolean hasNext()
			{
				return iter.hasNext();
			}
			public V next()
			{
				return entityToValue(iter.next());
			}
			public void remove()
			{
			}
		};
	}

SERIALIZATION /
	public static interface Serializer<V>
	{
bytesToObj(byte[] bytesClass<V> clz); // NOTE: if bytes is null, return null
		byte[] objToBytes(V obj); // NOTE: if obj is null, return null
	}
	private static final class JavaSerializer<V> implements Serializer<V>
	{
		public V bytesToObj(byte[] bytesClass<V> clz)
		{
			return SerializeUtil.bytesToObj(bytesclz);
		}
		public byte[] objToBytes(V obj)
		{
			return SerializeUtil.objToBytes(obj);
		}
	}
	public static class KryoSerializer<V> implements Serializer<V>
	{
		public V bytesToObj(byte[] bytesClass<V> clz)
		{
			return KryoUtil.bytesToObj(bytesclz);
		}
		public byte[] objToBytes(V obj)
		{
			return KryoUtil.objToBytes(obj);
		}
	}
	public static class FstSerializer<V> implements Serializer<V>
	{
		public FstSerializer()
		{
			 = FSTConfiguration.createDefaultConfiguration();
			.setShareReferences(false); // no circular references
		}
		@SuppressWarnings("unchecked")
		public V bytesToObj(byte[] bytesClass<V> clz)
		{
			return (bytes == null) ? null : (V) .asObject(bytes);
		}
		public byte[] objToBytes(V obj)
		{
			return (obj == null) ? null : .asByteArray(obj);
		}
	}

CACHE IMPLEMENTATION /
	private abstract class MemcachedBasedCache implements Cache<String, V>
	{
		protected final MemcacheService mc;
		{
			String gaeNS = NamespaceManager.get();
			String mcNS = (gaeNS == null) ?  : gaeNS + "-" + ;
			 = MemcacheServiceFactory.getMemcacheService(mcNS);
		}
	}
	private class JavaSerializeCache extends MemcachedBasedCache
	{
		@SuppressWarnings("unchecked")
		public V get(String key)
		{
			return (V) .get(key);
		}
		@SuppressWarnings("unchecked")
		public Map<String, V> get(Collection<Stringkeys)
		{
			return (Map<String, V>) (Map<String, ?>) .getAll(keys);
		}
		public void put(String key, V value)
		{
			.put(keyvalue);
		}
		public void put(Map<String, V> values)
		{
			.putAll(values);
		}
		public void delete(String key)
		{
			.delete(key);
		}
		public void deleteAll()
		{
			.clearAll();
		}
	};
	private class CustomSerializeCache extends MemcachedBasedCache
	{
		public V get(String key)
		{
			byte[] bytes = (byte[]) .get(key);
		}
		@SuppressWarnings("unchecked")
		public Map<String, V> get(Collection<Stringkeys)
		{
			Map<StringObjectvalues = .getAll(keys);
			Iterator<Entry<StringObject>> iter = values.entrySet().iterator();
			while (iter.hasNext())
			{
				Entry<StringObjectentry = iter.next();
				byte[] bytes = (byte[]) entry.getValue();
			}
			return (Map<String, V>) (Map<String, ?>) values;
		}
		public void put(String key, V value)
		{
			.put(key.objToBytes(value));
		}
		@SuppressWarnings("unchecked")
		public void put(Map<String, V> values)
		{
			// NOTE: we make a huge assumption here, that we can modify the passed map. by doing so we rely on "inside information" that
			// this is harmless given how 'iteratorFor' is implemented
			Iterator<Entry<StringObject>> iter = ((Map<StringObject>) (Map<String, ?>) values).entrySet().iterator();
			while (iter.hasNext())
			{
				Entry<StringObjectentry = iter.next();
				Object value = entry.getValue();
				entry.setValue(.objToBytes((V) value));
			}
			.putAll(values);
		}
		public void delete(String key)
		{
			.delete(key);
		}
		public void deleteAll()
		{
			.clearAll();
		}
	};
New to GrepCode? Check out our FAQ X