/* Copyright (c) 2009 Google Inc. * * 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 com.google.appengine.demos.sticky.server; import java.util.List; 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.users.User; import com.google.appengine.demos.sticky.client.model.Note; import com.google.appengine.demos.sticky.client.model.Surface; /** * A more typesafe wrapper around a {@link MemcacheService}. * * @author knorton@google.com (Kelly Norton) */ public class Cache { private static String createNotesId(String surfaceKey) { return NOTES_PREFIX + surfaceKey; } private static String createNotesId(User user, String surfaceKey) { return NOTES_PREFIX + user.getEmail() + surfaceKey; } private static String createSurfaceId(Key surfaceKey) { return SURFACE_PREFIX + KeyFactory.keyToString(surfaceKey); } private static String createSurfaceKeysId(String email) { return SURFACEKEYS_PRFIX + email; } /** * The memcache service to use for caching. */ private final MemcacheService memcache; private static final String NOTES_PREFIX = "NOTES/"; private static final String SURFACE_PREFIX = "SURFACE/"; private static final String SURFACEKEYS_PRFIX = "SURFACES/"; /** * Creates a new cache. * * @param memcache * the memcache service to use for caching objects */ public Cache(MemcacheService memcache) { this.memcache = memcache; } /** * Deletes the collection of notes that are cached for a surface. This is used * to invalidate cache entries. * * @param surfaceKey * the key for the surface */ public void deleteNotes(String surfaceKey) { memcache.delete(NOTES_PREFIX + surfaceKey); } /** * Deletes a {@link Surface} from the cache. This is used to invalidate cache * entries. * * @param surfaceKey */ public void deleteSurface(Key surfaceKey) { memcache.delete(createSurfaceId(surfaceKey)); } /** * Deletes a collection of surface keys for a user. * * @param email * the user's email */ public void deleteSurfaceKeys(String email) { memcache.delete(createSurfaceKeysId(email)); } /** * Attempts to fetch the collection of notes contained in a surface for a * particular user. If there is a value, but the user is not known to have * access to this surface, <code>null</code> will be returned. * * @param user * the user requesting access to the cache entry * @param surfaceKey * they key for the surface * @return a collection of notes if there is a cache entry, <code>null</code> * otherwise */ public Note[] getNotes(User user, String surfaceKey) { if (!canUserAccessNotes(user, surfaceKey)) { return null; } return (Note[]) memcache.get(createNotesId(surfaceKey)); } /** * Attempts to fetch a surface from cache. * * @param surfaceKey * the key of the surface * @return the surface if there is a cache entry, <code>null</code> otherwise */ public Surface getSurface(Key surfaceKey) { return (Surface) memcache.get(createSurfaceId(surfaceKey)); } /** * Attempts to fetch a collection of surface keys for a particular user. * * @param email * the email for the user * @return a collection of keys if there is a cache entry, <code>null</code> * otherwise */ @SuppressWarnings("unchecked") public List<Key> getSurfaceKeys(String email) { return (List<Key>) memcache.get(createSurfaceKeysId(email)); } /** * Adds the collection of notes in a surface to the cache and grants the user * access to that entry. * * @param user * the user that should be given access to the cache entry * @param surfaceKey * the key for the surface * @param notes * the collection of notes to cache * @return <code>notes</code>, for call chaining */ public Note[] putNotes(User user, String surfaceKey, Note[] notes) { memcache.put(createNotesId(surfaceKey), notes); allowUserToAccessNotes(user, surfaceKey); return notes; } /** * Adds a surface object to the cache. * * @param surfaceKey * the key of the surface * @param surface * the surface object * @return <code>surface</code>, for call chaining */ public Surface putSurface(Key surfaceKey, Surface surface) { memcache.put(createSurfaceId(surfaceKey), surface); return surface; } /** * Adds the collection of surface keys to the cache for a user (by email). * * @param email * the user's email * @param surfaceKeys * a collection of surface keys * @return <code>surfaceKeys</code>, for call chaining */ public List<Key> putSurfaceKeys(String email, List<Key> surfaceKeys) { memcache.put(createSurfaceKeysId(email), surfaceKeys); return surfaceKeys; } private void allowUserToAccessNotes(User user, String surfaceKey) { memcache.put(createNotesId(user, surfaceKey), Boolean.TRUE); } private boolean canUserAccessNotes(User user, String surfaceKey) { return memcache.contains(createNotesId(user, surfaceKey)); } }