#Who
Google App Engine (GAE/J)
App Engine SDK 1.9.18
JRE 1.7.0
#What
DatastoreServiceへのアクセス方法を考える。
#When, Where
サーバーサイド
DatastoreServiceへのアクセス部分
#Why
一つ一つのEntityに対してDatastoreへのアクセスを書くのは面倒臭い。
また、見通しが悪くなる。
処理を共通化できるのであれば共通化する。
#How
Person(名字、名前、身長)をDatastoreに保存する。
Personクラスを用意する。
public final class Person implements Storable<Person> {
static final String FIRST_NAME = "firstName";
static final String LAST_NAME = "lastName";
static final String HEIGHT = "height";
private final String firstName;
private final String lastName;
private final int height;
public Person(final String firstName, final String lastName, final int height) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.height = height;
}
public final String getFirstName() {
return firstName;
}
public final String getLastName() {
return lastName;
}
public final int getHeight() {
return height;
}
@Override
public Map<String, Object> getPropertyMap() {
return new HashMap<String, Object>() {
private static final long serialVersionUID = 1L;
{
put(FIRST_NAME, getFirstName());
put(LAST_NAME, getLastName());
put(HEIGHT, getHeight());
}
};
}
@Override
public Designable<Person> getDesign() {
return new PersonDesign();
}
}
必要なインターフェースはgetPropertyMapとgetDesign。
getPropertyMapはDatastoreに保存したい値とキー名のMapを返すようにする。
Designは以下のインターフェースを持つクラス。
public class PersonDesign implements Designable<Person> {
@Override
public Person create(final Map<String, Object> propertyMap) throws IllegalPropertyMapException {
for (final String propertyName : getPropertyNames()) {
if (!propertyMap.containsKey(propertyName)) {
throw new IllegalPropertyMapException();
}
}
final String firstName = (String) propertyMap.get(Person.FIRST_NAME);
final String lastName = (String) propertyMap.get(Person.LAST_NAME);
final long height = (long) propertyMap.get(Person.HEIGHT);
return new Person(firstName, lastName, (int) height);
}
@Override
public String getName() {
return "Person";
}
@Override
public List<String> getPropertyNames() {
return Arrays.asList(Person.FIRST_NAME, Person.LAST_NAME, Person.HEIGHT);
}
}
createはPersonをnewするための関数。
getNameはKindNameを返す。
getPropertyNamesはPersonが保存するプロパティのキー名を返す。
DatastoreServiceへのアクセスは以下のDaoを通して行う。
public class CoreDao {
private static final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
public final <T extends Storable<T>> void put(final T input) {
datastore.put(createEntity(input));
}
public final <T extends Storable<T>> void put(final Iterable<T> inputCollection) {
final List<Entity> entityList = new ArrayList<Entity>();
for (final T input : inputCollection) {
entityList.add(createEntity(input));
}
datastore.put(entityList);
}
public final <T> Iterable<T> get(final Designable<T> design) {
final Query q = new Query(design.getName());
final PreparedQuery pq = datastore.prepare(q);
final List<T> list = new ArrayList<T>();
for (final Entity entity : pq.asIterable()) {
final Map<String, Object> propertyMap = new HashMap<String, Object>();
for (final String propertyName : design.getPropertyNames()) {
propertyMap.put(propertyName, entity.getProperty(propertyName));
}
try {
list.add(design.create(propertyMap));
} catch (final IllegalPropertyMapException e) {
e.printStackTrace();
}
}
return list;
}
private <T extends Storable<T>> Entity createEntity(final T input) {
assert input != null;
final Entity entity = new Entity(input.getDesign().getName());
for (final Entry<String, Object> entry : input.getPropertyMap().entrySet()) {
final String propertyName = entry.getKey();
final Object propertyValue = entry.getValue();
entity.setProperty(propertyName, propertyValue);
}
return entity;
}
}
Datastoreへの保存はputを用いる。
Entityクラスの作成はcreateEntityを使用する。
DesignのgetNameでKind名を取得。
StorableインターフェースのgetPropertyMapで保存するプロパティをセットする。
Datastoreからの取得はgetを用いる。
getの引数にはDesignクラスを渡す。
DesignのcreateでPersonインスタンスを作る。
CoreDaoにはPersonクラスに依存した処理はないので、インターフェースを実装したクラスであれば共通に使うことができる。