読者です 読者をやめる 読者になる 読者になる

すがブロ

sugamasaoのhatenablogだよ

GAE on jRuby で Google アカウント認証をやってみる

GAE on jRuby with Sinatra でやってみるよ

元ネタは Users Java API の概要 - Google App Engine — Google Developers で、こいつを jRuby 上で sinatra を使った場合どうやるのか? という話。

ポイントは 2点

  • Java のスタティッククラスを使う場合は import 文を使う
  • Java の HttpServletRequest オブジェクトを取得する場合は、 sinatra の request オブジェクトの Hash に格納されている

この二つを踏まえればあとはそのまま移植すれば良い。

Java のスタティッククラスを使うためには

import する。そして、import の前に java を include する。あまり詳しく読んでいないので、おまじないとして考えておくw

include Java
import com.google.appengine.api.users.UserServiceFactory;

これでOK。あとは UserServiceFactory.hogehoge() で普通にメソッドにアクセスできる。

Java の HttpServletRequest オブジェクトを取得する場合
request.env["java.servlet_request"]

sinatra が持っている request オブジェクトの env に入っている。上記のようにすると HttpServletRequest オブジェクトがそのまま取れる。

サンプルアプリはこちら

ログインしていない場合は、ログイン用のリンクが出ます。ログインすると、各種の情報を出力します。
見た目がダサイのはご了承下さいw
ちなみに、一つだけ良くわからない点があるのだけど、isUserAdmin() が true を返す条件がわからない。何を持って Admin として判断しているの???

その他:Returning nil _server と言われて困る><

Mac の Leopard 付属の screen を使っていると、デプロイ時の appcfg.rb でパスワードを聞かれる場面で動作が重くてどうにもなくなる、という現象がある。
screen を辞める or MacPorts 経由での GNU screen を使っているとでないらしい。*1
参考:GNU screenで「Returning nil _server」といわれた場合の対処法 - Hello, world! - s21g

ソースはこんな感じ

config.ru
catrequire 'appengine-rack'
require 'app'

AppEngine::Rack.configure_app(
		:application => "hogehoge", 
		:version => xx
	)

run Sinatra::Application

:application とかは適宜変えてね

app.rb
catrequire 'rubygems'
require 'sinatra'

# Java のスタティックなクラスを使う為には import しておく必要がある
include Java
import com.google.appengine.api.users.UserServiceFactory;

template :layout do
  <<-EOS
<html>
<head>
  <title><%= @title %></title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h1><%= @title %></h1>
<ul><%= @message %></ul>
<hr />
<%= yield %>
</body>
</html>
EOS
end

get '/' do
  @title = "GAE sample"
  @message = "GAE sample"
  @body = ''
  @body << '<ul>'
  @body << '<li><a href="/user_sample">Google アカウント Java API 概要のjRuby での実装サンプル</a></li>'
  @body << '</ul>'
  erb %{
    <%= @body %><br />
  }
end

get '/user_sample' do
  @title = "google認証実験"
  @message = '<a href="http://code.google.com/intl/ja/appengine/docs/java/users/overview.html">Google アカウント Java API 概要</a>のjRuby での実装サンプル'

  userService = UserServiceFactory.getUserService();
  puts userService
  servlet = request.env["java.servlet_request"]
  if(servlet.getUserPrincipal)
    user = userService.currentUser()
    principal = servlet.getUserPrincipal()
    @body = ""

    # getUserService() で取得した UserService オブジェクト
    @body << "<h2>UserServiceFactory.getUserService()で取得した <a href='http://code.google.com/intl/ja/appengine/docs/java/javadoc/com/google/appengine/api/users/UserService.html'>UserService オブジェクト</a></h2>"
    @body << "isUserAdmin():#{userService.isUserAdmin()}<br />"
    @body << "isUserLoggedIn():#{userService.isUserLoggedIn()}<br />"
    @body << "<hr />"

    # currentUser() で取得した User オブジェクト
    @body << "<h2>UserServiceFactory.getUserService().currentUser() で取得した <a href='http://code.google.com/intl/ja/appengine/docs/java/javadoc/com/google/appengine/api/users/User.html'>User オブジェクト</a></h2>"
    @body << "getNickname():#{user.getNickname()}<br />"
    @body << "getAuthDomain():#{user.getAuthDomain()}<br />"
    @body << "getEmail():#{user.getEmail()}<br />"
    @body << "<hr />"

    # HttpServletRequest オブジェクトから取得した Principal オブジェクト
    @body << "<h2>request.env['java.servlet_request'].getUserPrincipal() で取得した <a href='http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/security/Principal.html'>Principal オブジェクト</a></h2>"
    @body << "getName():#{principal.getName()}"
    @body << "<hr />"

    # ログアウトリンク
    @body << "<a href='#{userService.createLogoutURL(servlet.getRequestURI)}'>logout</a>"

  else
    # ログインリンク
    @body = "<a href='#{userService.createLoginURL(servlet.getRequestURI)}'>login</a>"
  end

  erb %{
    <%= @body %><br />
  }
end

複数ファイルにする程でもないと思ったので ERB でソース内にべた書き。とりあえず奇麗さとかは目を瞑っていますw

あと、気になる点

GAE そのものの話なんだけど、一度作った My Applications のリソースって削除できないんですかね。10個しか作れないみたいなので慎重に使いたいのだけど、盛大に typo してなんとか闇に葬りたいのが一つあるんですけど><

*1:一時、これで半狂乱になったw