GAE + GWT プログラミングメモ

Google App Engine とGoogle Web Toolkit のメモ

タスクキューによるタスク実行

GAEは一つの処理を30秒以内に終わらせなければならないため、時間のかかる処理はタスクキューを使って分割実行する必要がある。

キューの登録はWEB-INF以下にqueue.xmlを作って登録する。
rateは追加されたキューの実行間隔。
1/sであれば、1秒に1回のペースで未実行のキューを実行する。

<queue-entries>
  <queue>
    <name>queueServlet</name>
    <rate>1/s</rate>
  </queue>
</queue-entries>

キューの追加はQueueFactory.getQueue("queueServlet")で作成したqueueに対し、addする。
TaskOptions.Builder.withUrlで、URLを指定することができるが、指定しない場合は、/_ah/queue/queueServletというURLが使われる。
TaskOptions.Builder.withParamでパラメータを指定することができる。

Queue queue = QueueFactory.getQueue("queueServlet");
for (int i = 0; i < 10; i++) {
  queue.add(TaskOptions.Builder.withParam("count", Integer.toString(i)));
}

指定したパラメータはHttpServletRequestのgetParameterで取り出せる。

public class QueueServlet extends HttpServlet {
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		Logger logger = Logger.getLogger(QueueServlet.class.getName());
		logger.info("count is " + req.getParameter("count"));
	}
}

QueueServletはweb.xmlに/_ah/queue/queueServletで登録すればよい。

  <servlet>
    <servlet-name>queueServlet</servlet-name>
    <servlet-class>com.kumoniji.server.QueueServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>queueServlet</servlet-name>
    <url-pattern>/_ah/queue/queueServlet</url-pattern>
  </servlet-mapping>

上の結果は以下のようになる。
1秒間隔で実行されているようには見えず、順番もばらばらな理由はよくわからない。
ともかく、順番に依存する処理は入れないほうが無難。

情報: count is 4
情報: count is 0
情報: count is 5
情報: count is 8
情報: count is 6
情報: count is 9
情報: count is 3
情報: count is 1
情報: count is 7
情報: count is 2


作成中のアニメ特化アンテナサイト
http://kumo2ji.appspot.com/

GWTでブラウザバックを実行する

GWTでブラウザバックを行うためには、HyperlinkとHistoryを使う。
まずは適当にUiBuilderでUIを作る。

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
	xmlns:g="urn:import:com.google.gwt.user.client.ui">
	<ui:style>
		
	</ui:style>
	<g:HTMLPanel>
		<g:VerticalPanel>
			<g:HorizontalPanel>
				<g:SimplePanel ui:field="hyperlink1Panel"/>
				<g:SimplePanel ui:field="hyperlink2Panel"/>
			</g:HorizontalPanel>
			<g:Label text="New Label" ui:field="resultLabel"/>
		</g:VerticalPanel>
	</g:HTMLPanel>
</ui:UiBinder> 

Hyperlinkのインスタンス化で第1引数に表示文字、第2引数にトークン(URLの#以降に追加される文字列)を指定する。
ブラウザバックを有効化させるためにはHistory.addValueChangeHandlerにハンドラを登録すればよい。
このとき、引数のevent.getValue()でHyperlinkのインスタンス化で第2引数に指定した文字列を取得することができる。

public class MainComposite extends Composite {

	private static MainCompositeUiBinder uiBinder = GWT
			.create(MainCompositeUiBinder.class);
	@UiField SimplePanel hyperlink1Panel;
	@UiField SimplePanel hyperlink2Panel;
	@UiField Label resultLabel;

	interface MainCompositeUiBinder extends UiBinder<Widget, MainComposite> {
	}

	public MainComposite() {
		initWidget(uiBinder.createAndBindUi(this));
		Hyperlink link1 = new Hyperlink("link1", "link1Token");
		hyperlink1Panel.add(link1);
		Hyperlink link2 = new Hyperlink("link2", "link2Token");
		hyperlink2Panel.add(link2);
		History.addValueChangeHandler(new ValueChangeHandler<String>() {
			@Override
			public void onValueChange(ValueChangeEvent<String> event) {
				resultLabel.setText(event.getValue());
			}
		});
	}
}


作成中のアニメ特化アンテナサイト
http://kumo2ji.appspot.com/

条件を指定してDatastoreから情報を取得する

Datastoreにキー名"http://otanews.livedoor.biz/"、
"title"プロパティ"萌えオタニュース速報"のEntityを登録した状況のとき、
"title"を指定して、Entityを取得する。

Entity entity = new Entity("blog", "http://otanews.livedoor.biz/");
entity.setProperty("title", "萌えオタニュース速報");
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
ds.put(entity);

Entityを取得するときに条件を指定するためにはQueryとFilterを用いる。
QueryはKind名を引数にインスタンス化する。
queryのsetFilterメソッドにプロパティの条件を指定する。
今回の場合は、"title"プロパティが"萌えオタニュース速報"のEntityを取得したいので、
FilterOperator.EQUALを用いる。
後は、queryをDatastoreServiceのprepareの引数にいれ、PreparedQueryにしてから、asQueryResultListメソッドで結果をQueryResultListとして得る。
PreparedQueryにはasListやasIteratorメソッドもあるが情報量はasQueryResultListが一番多い。(Cursor情報を持っている)
asQueryResultListの引数にFetchOptionsを指定する必要があるが、数の上限やCursorの指定がない場合は、FetchOptions.Builder.withDefaults()でよい。

Query query = new Query("blog");
query.setFilter(new FilterPredicate("title", FilterOperator.EQUAL, "萌えオタニュース速報"));
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
QueryResultList<Entity> entityList = ds.prepare(query).asQueryResultList(FetchOptions.Builder.withDefaults());


作成中のアニメ特化アンテナサイト
http://kumo2ji.appspot.com/

Keyを指定してDatastoreから保存情報の取り出す

http://kumo2ji.hatenablog.com/entry/2013/07/23/194931
Datastoreに保存した情報はKeyを指定して取り出すことができる。
KeyはKeyFactory.createKey(Kind名, キー名)で作る。
entityに登録したプロパティはgetPropertyで取得することができる。
getPropertyの戻り値はObjectなので、適宜キャストする。
キー名はentity.getKey().getName()で取得できる。

Key key = KeyFactory.createKey("blog", "http://otanews.livedoor.biz/");
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Entity entity = ds.get(key);
String title = (String)entity.getProperty("title");
String url = entity.getKey().getName();

作成中のアニメ特化アンテナサイト
http://kumo2ji.appspot.com/

DatastoreへのEntityの保存方法

GAEではNoSQLのDatastoreにデータを保存する。
Datastoreにデータを保存するためには、Entityを作り、DatastoreServiceのputに入れてやる。

EntityはKind名とキー名を指定してnewする。
これで、Datastoreで識別可能な名前をつけたことになるので、
保存したいプロパティをsetPropertyで指定していく。

Entity entity = new Entity("blog", "http://otanews.livedoor.biz/");
entity.setProperty("title", "萌えオタニュース速報");
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
ds.put(entity);

作成中のアニメ特化アンテナサイト
http://kumo2ji.appspot.com/