/*
* Copyright (c) 2006-2009 by Dirk Riehle, http://dirkriehle.com
*
* This file is part of the Wahlzeit photo rating application.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.wahlzeit.services;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
/**
* An ObjectManager creates/reads/updates/deletes Persistent (objects) from Google Datastore.
* It is an abstract superclass that relies on an inheritance interface and the Persistent interface.
*/
public abstract class ObjectManager {
/**
* All objects are now saved under this root key. In case of multi-tenancy this may change to several keys.
*/
public static final Key applicationRootKey = KeyFactory.createKey("Application", "Wahlzeit");
private static final Logger log = Logger.getLogger(ObjectManager.class.getName());
/**
* Reads the first Entity with the given key in the Datastore
*/
protected <E> E readObject(Class<E> type, Long id) throws IllegalArgumentException {
assertIsNonNullArgument(type, "type");
assertIsNonNullArgument(id, "id");
log.config(LogBuilder.createSystemMessage().
addMessage("Load Type " + type.toString() + " with ID " + id + " from datastore.").toString());
return OfyService.ofy().load().type(type).id(id).now();
}
/**
*
*/
protected void assertIsNonNullArgument(Object arg, String label) {
if (arg == null) {
throw new IllegalArgumentException(label + " should not be null");
}
}
/**
* Reads the first Entity with the given key in the Datastore
*/
protected <E> E readObject(Class<E> type, String id) throws IllegalArgumentException {
assertIsNonNullArgument(type, "type");
assertIsNonNullArgument(id, "id");
log.config(LogBuilder.createSystemMessage().
addMessage("Load Type " + type.toString() + " with ID " + id + " from datastore.").toString());
return OfyService.ofy().load().type(type).id(id).now();
}
/**
* Reads an Entity of the specified type where the wanted parameter has the given name, e.g. readObject(User.class,
* "emailAddress", "name@provider.com").
*/
protected <E> E readObject(Class<E> type, String parameterName, Object value) {
assertIsNonNullArgument(type, "type");
assertIsNonNullArgument(parameterName, "parameterName");
assertIsNonNullArgument(value, "value");
log.config(LogBuilder.createSystemMessage().
addMessage("Load Type " + type.toString() + " with parameter " +
parameterName + " == " + value + " from datastore.").toString());
return OfyService.ofy().load().type(type).ancestor(applicationRootKey).filter(parameterName, value).first()
.now();
}
/**
* Reads all Entities of the specified type, e.g. readObject(User.class) to get a list of all clients
*/
protected <E> void readObjects(Collection<E> result, Class<E> type) {
assertIsNonNullArgument(result, "result");
assertIsNonNullArgument(type, "type");
log.config(LogBuilder.createSystemMessage().
addParameter("Datastore: load all entities of type", type.getName()).toString());
List<E> objects = OfyService.ofy().load().type(type).ancestor(applicationRootKey).list();
log.config(LogBuilder.createSystemMessage().
addParameter("Datastore: number of loaded objects", objects.size()).toString());
result.addAll(objects);
}
/**
* Reads all Entities of the specified type, where the given property matches the wanted value e.g.
* readObject(User.class) to get a list of all clients
*/
protected <E> void readObjects(Collection<E> result, Class<E> type, String propertyName, Object value) {
assertIsNonNullArgument(result, "result");
assertIsNonNullArgument(type, "type");
assertIsNonNullArgument(propertyName, "propertyName");
assertIsNonNullArgument(value, "value");
log.info(LogBuilder.createSystemMessage().
addMessage("Datastore: Load all Entities of type " + type.toString() + " where parameter "
+ propertyName + " = " + value.toString() + " from datastore.").toString());
List<E> objects = OfyService.ofy().load().type(type).
ancestor(applicationRootKey).filter(propertyName, value).list();
log.config(LogBuilder.createSystemMessage().
addParameter("Datastore: number of loaded objects", objects.size()).toString());
result.addAll(objects);
}
/**
* Updates all entities of the given collection in the datastore.
*/
protected void updateObjects(Collection<? extends Persistent> collection) {
for (Persistent object : collection) {
updateObject(object);
}
}
/**
* Updates the given entity in the datastore.
*/
protected void updateObject(Persistent object) {
writeObject(object);
}
/**
* Writes the given entity to the datastore.
*/
protected void writeObject(Persistent object) {
assertIsNonNullArgument(object, "object");
if (object.isDirty()) {
log.info(LogBuilder.createSystemMessage().
addParameter("Datastore: Write object of type", object).toString());
OfyService.ofy().save().entity(object).now();
updateDependents(object);
object.resetWriteCount();
} else {
log.info(LogBuilder.createSystemMessage().
addParameter("Datastore: No need to update object", object).toString());
}
}
/**
* Updates all dependencies of the object.
*/
protected void updateDependents(Persistent object) {
// overwrite if your object has additional dependencies
}
/**
* Deletes the given entity from the datastore.
*/
protected <E> void deleteObject(E object) {
assertIsNonNullArgument(object, "object");
log.config(LogBuilder.createSystemMessage().addParameter("Datastore: delete entity", object).toString());
OfyService.ofy().delete().entity(object).now();
}
/**
* Deletes all entities of the type that have a property with the specified value, e.g.
* deleteObjects(PhotoCase.class, "wasDecided", true) to delete all cases that have been decided.
*/
protected <E> void deleteObjects(Class<E> type, String propertyName, Object value) {
assertIsNonNullArgument(type, "type");
assertIsNonNullArgument(propertyName, "propertyName");
assertIsNonNullArgument(value, "value");
log.info(LogBuilder.createSystemMessage().
addMessage("Datastore: delete entities of type " + type
+ " where property " + propertyName + " == " + value).toString());
List<com.googlecode.objectify.Key<E>> keys = OfyService.ofy().load().type(type).
ancestor(applicationRootKey).filter(propertyName, value).keys().list();
OfyService.ofy().delete().keys(keys);
}
/**
*
*/
protected void assertIsNonNullArgument(Object arg) {
assertIsNonNullArgument(arg, "anonymous");
}
}