目的はKind名の一覧を取得する事。Kind名さえわかれば、後は普通にDatastoreServiceFactory#getDatastoreService()を使って、Entityを読み込む事ができて、Entityが読み込めればそこから全propertyを取得できたりして、色々な事ができそう。ローカルからAppEngineにアップロードする時にも使えそうだし。Eclipse用にLocalDatastoreViewerPluginとかも作れそうだし。
……っていうエントリを書くつもりだったんだけど、SchemaやらEntityProtoやら色々要素が多すぎて、説明するのが大変に面倒になって来たので、ユーティリティクラスのコードだけ晒す事にしますw ゴメンナサイ、ゴメンナサイ。
AppEngineの起動と終了
Datastore周りの単体テストをする時とほぼおんなじ。
static final String DATASTORE_V3 = "datastore_v3";
static ApiProxy.Environment setUpDatastoreService(final String appId, final String versionId,
String applicationFolder) {
ApiProxy.Environment environment;
ApiProxy.setEnvironmentForCurrentThread(environment = new ApiProxy.Environment() {
public String getAppId() { return appId; }
public String getVersionId() { return versionId; }
public String getRequestNamespace() { return ""; }
public String getAuthDomain() { return "hoge.com"; }
public boolean isLoggedIn() { return true; }
public String getEmail() { return "fuga@hoge.com"; }
public boolean isAdmin() { return false; }
public Map<String, Object> getAttributes() {
Map<String, Object> map = new HashMap<String, Object>();
return map;
}
});
ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(applicationFolder)) {});
return environment;
}
static void tearDownDatastoreService() {
((LocalDatastoreService) ((ApiProxyLocalImpl) ApiProxy.getDelegate())
.getService(DATASTORE_V3)).stop();
ApiProxy.setDelegate(null);
ApiProxy.setEnvironmentForCurrentThread(null);
}Kind名の一覧を取得する
LocalDatastoreService#getSchema()ってのがあります。スキーマレスなのにgetSchame()とはなんのこっちゃってカンジですが、Datastoreのビューアが使っているのもこの情報です。
public static String[] getKinds(Environment environment) {
LocalDatastoreService datastoreService = (LocalDatastoreService) ((ApiProxyLocalImpl) ApiProxy
.getDelegate()).getService(DATASTORE_V3);
Schema schema = datastoreService.getSchema(null, (new StringProto()).setValue(environment
.getAppId()));
List<EntityProto> entityProtoList = schema.kinds();
List<String> kindList = new ArrayList<String>(entityProtoList.size());
for (EntityProto entityProto : entityProtoList) {
List<?> path = entityProto.getKey().getPath().elements();
Element element = (Element) path.get(path.size() - 1);
kindList.add(element.getType());
}
return kindList.toArray(new String[0]);
}特定のproperty名の一覧を取得する
Kind名がわれば実行時に取得できるので、あんまり必要無いかも。ちなみに、JDOを使っているとPOJOで定義した覚えが無いpropertyが混ざってくると思います。楽観的排他制御とか、ListPropertyのExtentで定義した制御の為にJDOが独自のpropertyを付加したものです。また、残念な事にインデックス対象でないpropertyは一覧から取得できません。
public static String[] getProperties(Environment environment, String kind) {
LocalDatastoreService datastoreService = (LocalDatastoreService) ((ApiProxyLocalImpl) ApiProxy
.getDelegate()).getService(DATASTORE_V3);
Schema schema = datastoreService.getSchema(null, (new StringProto()).setValue(environment
.getAppId()));
List<EntityProto> entityProtoList = schema.kinds();
for (EntityProto entityProto : entityProtoList) {
List<?> path = entityProto.getKey().getPath().elements();
Element element = (Element) path.get(path.size() - 1);
String type = element.getType();
if (kind.equals(type)) {
List<Property> properties = entityProto.propertys();
String[] propertyNames = new String[properties.size()];
for (int i = 0; i < propertyNames.length; i++) {
propertyNames[i] = properties.get(i).getName();
}
return propertyNames;
}
}
throw new RuntimeException("kind \"" + kind + "\" is not found.");
}使い方
SDKのコンテナを使った環境で使用しているデータファイル(war/WEB-INF/appengine-generated/local_db.bin)を使いたい場合は、以前書いたエントリ「#appengine のテスト用初期データを作成する」を参考に、アプリケーションのversionIdを確認しておく必要があります。
@Test public void test() {
Environment environment = setUpDatastoreService("shin1ogawa-app", "versionid.1", "war");
try {
String[] kinds = DatastoreUtil.getKinds(environment);
for (String kind : kinds) {
System.out.println(kind);
String[] properties = DatastoreUtil.getProperties(environment, kind);
for (String property : properties) {
System.out.println(" " + property);
}
}
} finally {
tearDownDatastoreService();
}
}importの宣言
import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; 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.dev.LocalDatastoreService; import com.google.appengine.tools.development.ApiProxyLocalImpl; import com.google.apphosting.api.ApiProxy; import com.google.apphosting.api.ApiBasePb.StringProto; import com.google.apphosting.api.ApiProxy.Environment; import com.google.apphosting.api.DatastorePb.Schema; import com.google.storage.onestore.v3.OnestoreEntity.EntityProto; import com.google.storage.onestore.v3.OnestoreEntity.Property; import com.google.storage.onestore.v3.OnestoreEntity.Path.Element;
0 件のコメント:
コメントを投稿