目的は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 件のコメント:
コメントを投稿