ラベル slim3 の投稿を表示しています。 すべての投稿を表示
ラベル slim3 の投稿を表示しています。 すべての投稿を表示

2010年11月23日火曜日

Slim3のGlobalTransaction

今更感がすごいあるけど、Slim3のトランザクションについてメモ。
まずは、普通のトランザクション。

public void update(final Key key) {
    // トランザクション開始
    final Transaction tx = Datastore.beginTransaction();
    fianl Model model = Datastore.get(tx, Model.class, key);

    mode.setName("hoge");
    Datastore.put(model)

    // コミット
    tx.commit();
}

GAEはデフォルトのトランザクションだと、単一のエンティティにしかトランザクションを貼れない。
でも、複数のエンティティを一緒に更新したい時ってのがあるわけで、そういう時に
使用するのが、グローバルトランザクション。

public void update(final Key hogeKey, final Key fugaKey) {
    // トランザクション開始
    final GlobalTransaction gtx = Datastore.beginGlobalTransaction();
    fianl HogeModel hogeModel = gtx.get(HogeModel.class, hogeKey);
    fianl FugaModel fugaModel = gtx.get(FugaModel.class, fugaKey);

    hogeModel.setName("hoge");
    fugaModel.setName("fuga");
    gtx.put(hogeModel, fugaModel)

    // コミット
    gtx.commit();
}

上記の様にすれば、複数のエンティティにまたがる処理を同一トランザクションで処理出来ます。
ちなみに、上記で使用しているputメソッドの引数は可変長引数なので、
2つ以上のエンティティの更新が可能です。

ここで、注意して欲しいのがqueryメソッドはトランザクションのサポート外ってところ。
なので、エンティティのプロパティにKeyを生成するための文字列を持たせておくのが
ベターでしょうか。(更新時等にKeyでエンティティを取得できるようにするため)

2010年7月7日水曜日

slim3使用時のgoogle認証の使い方ではまったところ

slim3使用時のgoogle認証の使い方のハマリどころ。

例えば
http://アプリケーションID/private/
というURLにアクセスした場合に、private下にはすべてgoogle認証をかけたい場合、
以下のようなFilterを作成します。

/**
 * google認証を行うFilterクラス
 */
public class MemberFilter implements Filter {

  @Override
  public void doFilter(ServletRequest request, ServletResponse response,
             FilterChain filterChain) throws IOException, ServletException {

    final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    final UserService userService = UserServiceFactory.getUserService();

    // リクエストのあったURL
    final String requestUri = httpServletRequest.getRequestURI();

    // googleアカウントにログインしているかを判定するUtilクラス(後述)
    if (AccountUtils.isGoogleLogin(httpServletRequest) == false) {
      ((HttpServletResponse) response).sendRedirect(userService.createLoginURL(requestUri));
      return;
    }

    // ログイン成功
    filterChain.doFilter(request, response);

  }

  @Override
  public void destroy() {
  }

  @Override
  public void init(FilterConfig arg0) throws ServletException {
  }
}

/**
 * google認証を判定するUtilクラス
 */
public class AccountUtils {

  /**
   * googleアカウントにログインしているかを判定する。
   *
   * @param request
   * @return ログインしていればtrue, していなければfalse
   */
  public static boolean isGoogleLogin(final HttpServletRequest request) {

    final UserService userService = UserServiceFactory.getUserService();
    final Principal principal = request.getUserPrincipal();

    if (principal == null || userService.isUserLoggedIn() == false) {
      return false;
    }

    return true;
  }
}


以上です。
この例だと、「/private/」にアクセスした場合に、MembeerFilterクラスのdoFilterが呼ばれ、
17行目のif文でgoogleアカウントにログインしているかをチェックし、
falseならばログインページにリダイレクトされます。

ここで、注目して欲しいのが、14行目のrequestUri。
これがログイン後にリダイレクトされるパスを示しています。
18行目のuserService.createLoginURL(requestUri)では、ログインページのパスを作成し、
このパスには、ログイン後にアクセスするURL、つまり今回の例でいう「/private/」が含まれています。
ただ、ここでハマリどころなのですが、実際にアクセスしようとしたURLが「/private/」となっていても、
14行目で取得できるurlは「/private/index.jsp」。
つまり、ログイン後に飛ばされパスは「/private/index.jsp」となってしまいます。
Slim3では、jspファイルに直接アクセスできないようになっているので、
もちろんこれは403エラーになってしまいます。

これを解決するためには、MemberFilterクラスの18行目を、
((HttpServletResponse) response).sendRedirect(userService.createLoginURL(requestUri.replace("index.jsp", "")))

と修正して上げれば、ログイン後に飛ばされるパスから「index.jsp」が削除されるので、
問題なくControllerを経由してページにアクセスできるようになります。