X

JDOをGAEのデータストアに保存/取得する

JDO(Javaデータオブジェクト)を利用して、GoogleAppEngineのデータストアへアクセスする方法を紹介します。
Low Level APIでGAEのデータストアにアクセスすると比べるとデータベースの仕組みを理解するには難しくなってしまっていますが、とても簡単に、複数データをまとめてオブジェクトとして扱える便利な手法です。

PersistenceManagerクラスでデータストアにアクセスする

メソッド名説明
PersistenceManagerのインスタンス生成時PersistenceManagerFactoryクラスをつかって生成すること
makePersistent()オブジェクトの永続化(データストアへの保存)を行う
newQuery()指定文字列の検索クエリを作成する。
検索クエリをexecuteメソッドで実行することでJDOを取得できる

JDOを使ってデータストアにアクセスするには、PersistenceManagerクラスのインスタンスが必要です。インスタンス生成にはPersistenceManagerFactoryクラスを利用します。
JDOで定義される永続性(保存される)オブジェクトは通常のJavaのクラスです。感覚としてはインスタンスをそのまま保存し、使いたいときにいつでも取り出せる便利な仕組みです。インスタンス=Javaデータオブジェクトのような関係ですね。

データストアの利用準備

前回のサンプルをベースに、掲示板への投稿(データストアへの保存)と表示(データストアからの取得)してみましょう。

まず、データストアへアクセスするため、PersistenceManagerFactoryクラスを利用するPMFクラスを作成します
■src/PMF.java

package org.jpn.techbooster.sample.guestbook;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
    private static final PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");

    private PMF() {}

    public static PersistenceManagerFactory get() {
        return pmfInstance;
    }
}

PMFクラスのgetメソッドでPersistenceManagerFactoryクラスのインスタンスが取得できます。
PersistenceManagerFactoryのインスタンス生成は時間がかかる重い処理ですが、インスタンスは再利用可能なため、一度つくってしまえば繰り返す必要はありません。

データストアへの保存

データストアへの保存はPersistenceManagerクラスのmakePersistentメソッドを利用します。
インスタンスをmakePersistentメソッドに引き渡しすだけですので、とても簡単です。
■src/SignGuestbookServlet.java

@SuppressWarnings("serial")
public class SignGuestbookServlet extends HttpServlet {

    public void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws IOException {

        String content = req.getParameter("content");
        Date date = new Date();
        Greeting greeting = new Greeting("ペンギン1号", content, date);

        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            pm.makePersistent(greeting);
        } finally {
            pm.close();
        }

        resp.sendRedirect("/guestbook.jsp");
    }
}

11行目、データストアにアクセスするため、PersistenceManagerのインスタンスを取得します。
13行目、PersistenceManagerクラスのmakePersistentメソッドを使ってGreetingクラスをデータストアに保存します
15行目、closeメソッドでアクセスを完了します

データストアから取得する

掲示板ではメッセージを投稿するだけでなく一覧表示する必要があります。
以下のサンプルでは、データストアへ保存したメッセージを取得して表示しています。
検索クエリを工夫することで日付ソートする、など様々な条件での抽出が可能です。
■war/WEB-INF/guestbook.jsp

<html>
  <head>
    <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
  </head>

  <body>

...省略...

<%
    PersistenceManager pm = PMF.get().getPersistenceManager();
    String query = "select from " + Greeting.class.getName() + " order by date desc";
    List<Greeting> greetings = (List<Greeting>) pm.newQuery(query).execute();
    if (greetings.isEmpty()) {
%>
<p>The guestbook has no messages.</p>
<%
    } else {
        for (Greeting g : greetings) {
            if (g.getAuthor() == null) {
%>
<p>An anonymous person wrote:</p>
<%
            } else {
%>
<p><b><%= g.getAuthor() %></b> wrote:</p>
<%
            }
%>
<blockquote><%= g.getContent() %></blockquote>
<%
        }
    }
    pm.close();
%>
  </body>
</html>

JDOデータオブジェクトであるGreetingクラスをデータストアから検索しています。
PersistenceManagerのインスタンスを取得した後、
12行目、検索クエリとなる文字列queryを作っています(日付ソートを条件に加えています)。

13行目、PersistenceManagerクラスのnewQueryメソッドで新しいクエリを作成、データストアからGreetingを取得します。
List greetingsには検索クエリのexecuteメソッドで実行した結果が格納されています。
14行目以降、取得したデータオブジェクトgreetingsを表示する処理を行います。

今回はサンプルということもあり、サニタイジング処理が行われていません。
(実際に作成する際は、ユーザの入力データをそのまま表示しないようにしてください。意図しないHTMLタグや悪意あるコードが実行される虚弱性があります)

おつかれさまでした!

mhidaka: Software Engineerだよ。DroidKaigi Organizer / Androidと組込とRe:VIEW。techbooster主宰。mhidaka's writings http://booklog.jp/users/mhidaka 技術書典! http://techbookfest.org