All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.objectify.impl.SessionCachingAsyncObjectifyImpl Maven / Gradle / Ivy

Go to download

*** THIS VERSION UPLOADED FOR USE WITH CEDAR-COMMON, TO AVOID DEPENDENCIES ON GOOGLE CODE-BASED MAVEN REPOSITORIES. *** The simplest convenient interface to the Google App Engine datastore

The newest version!
package com.googlecode.objectify.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

import com.google.appengine.api.datastore.AsyncDatastoreService;
import com.google.appengine.api.datastore.Transaction;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.Query;
import com.googlecode.objectify.Result;
import com.googlecode.objectify.cache.TriggerSuccessFuture;
import com.googlecode.objectify.util.NowFuture;
import com.googlecode.objectify.util.SimpleFutureWrapper;

/**
 * Extends the AsyncObjectifyImpl to add a session cache.  Note that it only needs
 * to override a few key methods.
 * 
 * @author Jeff Schnitzer 
 */
public class SessionCachingAsyncObjectifyImpl extends AsyncObjectifyImpl
{
	/** Value which gets put in the cache for negative results */
	protected static final Object NEGATIVE_RESULT = new Object();

	/** The cache is a simple hashmap */
	protected Map, Object> cache = new HashMap, Object>();
	
	/**
	 */
	public SessionCachingAsyncObjectifyImpl(ObjectifyFactory fact, AsyncDatastoreService ds, Transaction txn)
	{
		super(fact, ds, txn);
	}

	/* (non-Javadoc)
	 * @see com.google.code.objectify.AsyncObjectify#get(java.lang.Iterable)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public  Result, T>> get(final Iterable> keys)
	{
		final List> needFetching = new ArrayList>();
		Map, T> foundInCache = new LinkedHashMap, T>();
		
		for (Key key: keys)
		{
			T obj = (T)this.cache.get(key);
			if (obj == null)
				needFetching.add(key);
			else if (obj != NEGATIVE_RESULT)
				foundInCache.put((Key)key, obj);
		}

		if (needFetching.isEmpty())
		{
			// We can just use the foundInCache as-is
			Future, T>> fut = new NowFuture, T>>(foundInCache);
			return new ResultAdapter, T>>(fut);
		}
		else
		{
			Future, T>> fromDatastore = super.get(keys).getFuture();

			// Needs to add in the cached values, creating a map with the proper order
			Future, T>> wrapped = new SimpleFutureWrapper, T>, Map, T>>(fromDatastore) {
				@Override
				protected Map, T> wrap(Map, T> fetched) throws Exception
				{
					Map, T> result = new LinkedHashMap, T>();
					
					for (Key key: keys)
					{
						T t = (T)cache.get(key);
						if (t != null)
						{
							if (t != NEGATIVE_RESULT)
								result.put((Key)key, t);
						}
						else
						{
							t = fetched.get(key);
							if (t != null)
							{
								result.put((Key)key, t);
								cache.put(key, t);
							}
							else
							{
								cache.put(key, NEGATIVE_RESULT);
							}
						}
					}
					
					return result;
				}
			};
			
			return new ResultAdapter,T>>(wrapped);
		}
	}

	/* (non-Javadoc)
	 * @see com.google.code.objectify.AsyncObjectify#put(java.lang.Iterable)
	 */
	@Override
	public  Result, T>> put(final Iterable objs)
	{
		// Unfortunately we can't put the data in the session cache right away because
		// the entities might not have populated ids.  They keys/ids only get populated
		// when the data is fetched.
		//for (T t: objs)
		//	this.cache.put(this.factory.getKey(t), t);
		//
		//return super.put(objs);
		
		Result, T>> orig = super.put(objs);
		
		Future, T>> triggered = new TriggerSuccessFuture, T>>(orig.getFuture()) {
			@Override
			protected void success(Map, T> result)
			{
				for (Map.Entry, T> entry: result.entrySet())
					cache.put(entry.getKey(), entry.getValue());
			}
		};

		return new ResultAdapter, T>>(triggered);
	}

	/* (non-Javadoc)
	 * @see com.google.code.objectify.Objectify#delete(java.lang.Iterable)
	 */
	@Override
	public Result delete(Iterable keysOrEntities)
	{
		for (Object obj: keysOrEntities)
			this.cache.put(this.factory.getKey(obj), NEGATIVE_RESULT);

		return super.delete(keysOrEntities);
	}

	/* (non-Javadoc)
	 * @see com.googlecode.objectify.Objectify#query()
	 */
	@Override
	public  Query query()
	{
		return new SessionCachingQueryImpl(this.factory, this.sync, this.cache);
	}
	
	/* (non-Javadoc)
	 * @see com.googlecode.objectify.Objectify#query(java.lang.Class)
	 */
	@Override
	public  Query query(Class clazz)
	{
		return new SessionCachingQueryImpl(this.factory, this.sync, this.cache, clazz);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy