2013年10月15日火曜日

play-pac4j : Play! Framework 2.2 で OAuth(失敗 -> 2.1 では成功)

ちょっと前のエントリで Play! Framwork で twitter4j を使うのに SecureSocial というのを使ってみましたが、別のものということで今度は pac4j というのを使ってみます。定義によると
pac4j is a Profile & Authentication Client for Java (it's a global rebuilding of the scribe-up library)
だそうです。それをさらに Play! Framework から利用しやすいように play-pac4j というものがあるようですね。早速使ってみます。

まずは dependency の解決です。上のガイドに従うと、Twitter を使うためには、play-pac4j_java と pac4j-oauth が必要なようですね。Maven の central repo では最新はそれぞれ 1.1.1 と 1.4.1 です。以下のように build.sbt に追加します。(このファイル、2.x では project/Build.scala だったはずなんですが、変わったんですね・・・)

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  "org.twitter4j" % "twitter4j-core" % "3.0.4",
  "org.pac4j" % "play-pac4j_java" % "1.1.1",
  "org.pac4j" % "pac4j-oauth" % "1.4.1"
)  

前回やったように、IntelliJ IDEA を一度止めて play idea してから開きなおすのが手っ取り早いようです。ではコードの変更です。
  1. コントローラーが継承しているクラスを Controller から JavaController に
  2. Global.onStart() で TwitterClient を登録
  3. ログインを要求したいコントローラーメソッドに @RequiresAuthentication を追加
  4. routes に callback を追加
具体的には
1
import org.pac4j.play.java.JavaController;

public class Application extends JavaController {
2
public class Global extends GlobalSettings {
    @Override
    public void onStart(Application application) {
        final TwitterClient twitter = new TwitterClient(CONSUMER_KEY, CONSUMER_SECRET);
        final Clients clients = new Clients("http://localhost:9000/callback", twitter);
        Config.setClients(clients);
3
    @RequiresAuthentication(clientName="TwitterClient")
    public static Result top() {
4
# For pac4j
GET   /callback               org.pac4j.play.CallbackController.callback()
POST  /callback               org.pac4j.play.CallbackController.callback()
GET   /logout                 org.pac4j.play.CallbackController.logoutAndRedirect()
おお、結構作業量が少なくていい感じ。早速実行してみましょう。
[info] play - Application started (Dev)
Uncaught error from thread [play-akka.actor.default-dispatcher-7] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[play]
java.lang.AbstractMethodError
あっさりオワタw
まだ 2.2 がサポートされてないんですね。この方も嘆いてますが、Play! Framework ってバージョン間の互換性がなさすぎる・・・。

仕方ないので Play! Framework を 2.1.5 にしてみます。2.1.5 で play new して作った雛形から、Build.scala をコピーして、build.sbt 内に加えた変更を移動します。あとは念のため diff で差分が出た build.properties とか plugins.sbt とかを直していざテスト。

おっ!
うまくいきました。これは結構簡単。

最後にお約束の twitter4j のインスタンス作り。
    @RequiresAuthentication(clientName="TwitterClient")
    public static Result login() throws TwitterException {
        final TwitterProfile profile = (TwitterProfile) getUserProfile();
        TwitterFactory factory = new TwitterFactory(new ConfigurationBuilder().setOAuthConsumerKey(CONSUMER_KEY).setOAuthConsumerSecret(CONSUMER_SECRET).build());
        Twitter tw = factory.getInstance(new AccessToken(profile.getAccessToken(), profile.getAccessSecret()));
これでうまくいきました。

2013年9月30日月曜日

Heroku を試す(7)~ Play! Framework 2.2 を IntelliJ IDEA で動かしてみる

実は前の記事はだいぶ前に書いていて公開し忘れていたものでした。このたびもう一度使ってみようと思ったので、新しいエントリを書く前にとりあえず公開したものです。で、もう一度やろうとしたらいろいろバージョンも変わっていたので変化部分を。

まず前回はあきらめた git のバージョンですが、ちゃんとバージョンをあげておきました。

$ git --version
git version 1.7.11.3

これなら文句は言われまいw IntelliJ IDEA を起動しましたが、確かに何も警告は出ませんでした。勝った!(←何に?w)これで IDEA のほうも最新バージョンで進めます。

Play! Framework のほうですが、最新は 2.2.0 になっていました。なにやら嫌な予感が・・・。Play! Framework 自体は好きなんですが、バージョンアップ時の挙動が結構変わるのが難儀するんですよね。まあいいか、早速プロジェクトを作ってみます。


orz
こんな予想的中してもうれしくないw まだIDEAのプラグインが対応してないのかな。ここは気を取り直して、Play側から作って IDEA 対応を試みます。

$ play new sample-app
$ cd sample-app
$ play
[sample-app] $ idea

これを IDEA から開くと、無事開けました。

前回なぜはまらなかったのか不明ですが、デフォルトでは起動すると 9000 番ポートにつなぎに行きます。しかし他のアプリケーションで使っていると当然失敗します。直接コマンドラインから指定するときは

$ play run --http.port=9001

のようにすればいいのですが、IDEA からの起動だと play に直接コマンド渡せるわけではないので。結論としては Run/Debug Configurations のところで、Play 2 の起動構成を出し、 JVM Options に -Dhttp.port=9001 のように足せばポートが指定できます。

これで起動、デバッグ、あとは heroku へのデプロイ等は問題なくできました。しかし初回の push は長い・・・。いろんなライブラリの解決してるからっぽいですけど。あとはデータベースへの接続やバージョン管理(GAEで version.application.appspot.com で試せるやつのような)のやり方を学ばねば。

2013年9月29日日曜日

Heroku を試す(6)~ Play! Framework 2.0 を動かしてみる

さてなんとなく感じがつかめてきたところで今度は Play! Framework を使ってみようと思います。せっかくなのでちゃんと対応している(はずの)IntelliJ IDEA を使ってみましょう。Eclipse でやると結局のところ Java 以外のところはテキストエディタとして使うことが多くていまいち便利になった感がないので。

早速起動してプロジェクトを作成・・・ってあれ?前はここに Play! って出てた気がしたんですが・・・。恐らく完全な気のせいで、プラグインを入れなければいけないようです。それじゃ Eclipse と同じとかは思わないことにしますさくっと入れますw すると、おお、確かにでてきましたね!

実は最初何度やってもバージョンを変えてもうまくいかなくて相当悩んだんですが、ここに問題があがっていてこれかと思って普通にコマンドラインから play new してもエラーになったんです。なんだろうと思ったら Play! Framework 自体を /opt (つまり書き込み不可な場所)に入れていたのが原因だそうで。どうせ読み書き可能にしなきゃいけないのならユーザーのディレクトリに入れて指定したところうまくいきました。この思想がいいかどうかは別として。

さてこれを Heroku に上げてみましょう。Heroku のほうPlay! Framework のほうと両方に異なる文書がありますが、スクロールバーが短い(w) Play! のほうにしたがってみます。

まずは Store your application in git の部分。git コマンドをたたけばいいわけですが、IDEA から行きましょう。VCS > Import into Version Control > Create Git Repository で・・・

orz

厳しいっすw

git は rpm 経由で入れていて上げるのはまあまあ面倒なので、12.0.1 を再度引っ張り出してきて構成しました。するとコマンド自体は動いていたのか、既に git の管理下になっているようです。

では heroku の設定を。
$ heroku create sdk0815-sample2
Creating sdk0815-sample2... done, region is us
http://sdk0815-sample2.herokuapp.com/ | git@heroku.com:sdk0815-sample2.git
Git remote heroku added
これでリモートがセットされたはず。 しかし
$ git push heroku master
Warning: Permanently added the RSA host key for IP address '50.19.85.154' to the list of known hosts.
error: src refspec master does not match any.
error: failed to push some refs to 'git@heroku.com:sdk0815-sample2.git'
うーむ。これは何のエラーだろう。いろいろ調べたらどうやら何も push するものがないときに出るエラーみたいですね。 git commit したら確かにコミットされたので commit まではされてなかったんですね。
#IDEA からやるべきだったんですがついコマンド打っちゃいました。プロジェクトを右クリックで Git > Commit Directory... で全部 commit できます。

さて今度は push したらずっと待たされました。いけー。どりゃー。おおおお!

やったー!・・・ってあれ、こんな殺風景なはずは・・・w

どうもフレームワーク動いてないですね、これ。前に作ったときにあった Procfile にあたるものが必要なのかも。と思ったらちゃんと書いてありました。 これを作って再度挑戦です。また待たされました。いつ終わるのかな~。終わった!

変化なしw

よく考えてみると、この "Your new application is ready." という文字列って、ソースコードの中では
@(message: String)

@main("Welcome to Play 2.1") {
    
    @play20.welcome(message, style = "Java")
    
}

となっていて、文字列はコントローラである Application.java から送られてきています。ということはフレームワークは動いているということかな? @play20 というカスタムタグ(?)が動いていないようだと。

まあちょっと玉虫色な感じもしますが、とりあえず動かせるところまではもってこれました。実際に何か作るかは意欲と時間とネタ次第です。

2013年8月2日金曜日

IntelliJ IDEA で maven の dependency を解決する

ほんのちょっとした Tips 的ですが、しばらく悩んだので。

IntelliJ IDEA で Maven Module を指定して Project を作成します。ここまではよし。しかし実際に作成された pom.xml に dependency を追加する方法がわかりませんでした。すると、いくつか方法はあるようですが、そのうちの1つはエディターから Alt+Enter 等で出てくるメニューから "Add Maven Dependency..." を選べばよいと。ふむふむ。出てくるダイアログで文字列検索すれば・・・
 でてこない。 orz
全く出てこないわけではなく、何も入れてないときは ant とか commons なんとかとかそのへんは出てるんですよね。うーむ。どうもローカルにあるリポジトリだけを見てるっぽいですね。

そんなときは File > Settings から Maven > Repositories を選ぶと以下のような画面になるので、central repo を選んで Update を押せばよいようです。
その後同じ操作をすると、
めでたしめでたし。

2013年6月26日水曜日

Play! Framework で twitter4j を使う

久しぶりにちょっと時間ができたので遊んでみました。

表題のとおりです。とりあえず OAuth でログインできるところまで行きたいですね。

まずは twitter4j を追加します。これまでは jar をコピーしていたのですが、そんなことするよりずっと簡単な方法があります。Managed Dependency という項に書かれているように Build.scala に依存を書けば勝手に解決してくれます。フレームワークって大事ですね。
  val appDependencies = Seq(
    "org.twitter4j" % "twitter4j-core" % "3.0.3"
  )
これだけ・・・。便利になりました。

早速コードを書き始めると・・・おや、Play! を再起動しても IntelliJ IDEA では解決してくれないですね。うーむ。File > Invalidate Caches なんかもやってみましたがだめです。どうやら
$ play idea
を実行しないとだめみたいです。このへんはもう少し便利になってくれるとうれしいですけどね。まあこれで特に問題はないです。

では OAuth のページを作成しましょう。

と思ったらなんか便利そうなものを見つけました。 ここに書かれている SecureSocial なるものを使ってみますか。また dependency をつけます。
  val appDependencies = Seq(
    "org.twitter4j" % "twitter4j-core" % "3.0.3",
    "securesocial" %% "securesocial" % "master-SNAPSHOT"
  )

  val main = play.Project(appName, appVersion, appDependencies).settings(
    // Add your own project settings here
    resolvers += Resolver.url("sbt-plugin-snapshots", new URL("http://repo.scala-sbt.org/scalasbt/sbt-plugin-snapshots/"))(Resolver.ivyStylePatterns)
  )
この時点では Play! 2.1 には spapshot を使えとあるのでそうしてみました。これで同じように play idea も実行して解決させておきます。routes は書いてあるものそのままで。play.plugins からは不要な Provider を消します。
9994:securesocial.core.DefaultAuthenticatorStore
9995:securesocial.core.DefaultIdGenerator
9997:securesocial.controllers.DefaultTemplatesPlugin
9998:service.InMemoryUserService
10000:securesocial.core.providers.TwitterProvider
こんな感じで。あ、sample から InMemoryUserService を持ってきました。動作確認に使えます。次に securesocial.conf を作って application.conf から include します。
securesocial {
  onLoginGoTo=/
  onLogoutGoTo=/login
  ssl=false

  twitter {
     requestTokenUrl="https://twitter.com/oauth/request_token"
     accessTokenUrl="https://twitter.com/oauth/access_token"
     authorizationUrl="https://twitter.com/oauth/authenticate"
     consumerKey="****"
     consumerSecret="****"
  }
}
いよいよ実行です・・・。とその前に、ログインしてないとだめなメソッドに @SecureSocial.SecuredAction アノテーションをつけます。
    @SecureSocial.SecuredAction
    public static Result index() {
        Identity user = (Identity) ctx().args.get(SecureSocial.USER_KEY);
        final String userName = user != null ? user.fullName() : "guest";
        return ok(index.render("Logged on as " + userName + "."));
    }
では実行です。/login にアクセスすると
まずはこのようにログインの画面が出ます。ここで t のアイコンをクリックするといつものツイッターの認証画面に飛ばされます。そこで認証を行うと
のようになります。やったー。・・・ツイッターだけだと正直楽になったかどうか微妙ですがw ほかのサービス(facebook とか)でもログインできるのでその手のサービスを作りたいときは便利なのは間違いないですね。

さてこれでログインはできましたが、twitter4j が使えなければ意味がないわけで。ログインした後に実行されるメソッドの中身を変えます。

        String ret = "Unknown";
        Identity user = (Identity) ctx().args.get(SecureSocial.USER_KEY);
        if (user != null) {
            Twitter twitter = new TwitterFactory().getInstance();
            twitter.setOAuthConsumer(Play.application().configuration().getString("securesocial.twitter.consumerKey"),
                    Play.application().configuration().getString("securesocial.twitter.consumerSecret"));
            AccessToken accessToken = new AccessToken(user.oAuth1Info().get().token(), user.oAuth1Info().get().secret());
            twitter.setOAuthAccessToken(accessToken);
            User u = twitter.verifyCredentials();
            ret = "Logged on as " + u.getName() + "(@" + u.getScreenName() + ") followed by " + u.getFollowersCount() + " followers.";
        }
        return ok(index.render(ret));
実行すると・・・
 できたー。

2013年5月24日金曜日

Heroku を試す(5)~コードを変更してデプロイしてみる

ずいぶん間があいてしまいました。興味の向く先がいろいろ変わるのはいいのか悪いのかわからないですが・・・。前々回の続きです。

しかしこのページ、殺風景ですね。
と思ったら
 あらら、エラーになってますね。早速直してみましょう。

直すためにはどうやってこのコードが動いているのかを知る必要があります。ソースコードを開いてみます。右にあるように、Main.java と HelloServlet.java があります。どう見ても Main が怪しい(w)ので開いてみると、思いっきり main メソッドがありますね。へぇ、これって任意の(サーブレットコンテナだけでなく)Java コードを実行できちゃったりするんですかね?それはそれで面白いような怖いような・・・。

ひとつ疑問なのは、この main メソッドをどうやって見つけているのか、ということ。これがわからないと間違ってどこかのクラスに main メソッドを作ってしまうととたんにアプリが動かなくなったりということもありうるのでは。ファイルを眺めていると大体のファイルは予想がつくものですが、中に Procfile なるファイルがあります。これは何だろう。
web:    java $JAVA_OPTS -cp target/classes:target/dependency/* com.example.Main
ほほう。どうやらこれがその答えだったようですね。なので一安心w

で、本題の修正です。もう twitter.github.com は twitter.github.io に変わっているために殺風景なページになっているのでしょうね。ローカルで編集して試します。Main クラスを Java Application として起動します。Eclipse 内では m2e のおかげでクラスパス等は解決されているはずです。 起動しました。8080 にアクセスしたらちゃんと同じページが出てきます。よしよし。Edit > Find/Replace で github.com を github.io に Replace します。保存してリロードすると・・・
めちゃめちゃ今どきになったじゃないですかw

さてこの変更をコミットしましょう。チュートリアルに戻って、まずは変更をコミットです。それから Push to Upstream をクリックしてしばし待ちます。すると無事サイトのほうも更新されます。なるほど。

2013年4月29日月曜日

Eclipse のプロジェクトを IntelliJ IDEA に

ちょっと Heroku の話はお休みして。#f1yosou のサイトはとうとう GAE/J の無料分では Stats が計算できなくなり、あえなく Stats を閉鎖する運びとなりました。で、この際裏で進めていたサイト全体のリニューアルを先にしてしまおうかと思ったのです。なぜなら新しいデザインのほうはまだ Stats ができてなくて時間がかかるなと思っていたんですが、現行のほうも Stats が使えないならもう移行してしまってもいいわけですね。

とはいえまだ公開できるレベルではないのでもう少し実装・テストをする必要があります。なのでこの際現状は Eclipse で開発しているのですが、IntelliJ IDEA を使ってみようと思いました。Java 部分はそれほど大差ないかと思うのですが、Velocity とかこれまではほぼ自前/手書きだったのが便利になるのではという期待もこめて。


ソースコードは subversion にチェックインされているので現状 Eclipse にあるコードはすべてチェックインしておきます。そこからチェックアウトする流れで。 IntelliJ IDEA から VCS > Checkout from Version Control > Subversion を選びます。すると右のようなダイアログがでるので、リポジトリの情報を入力して選択します。その後どこに展開するか場所をしていします。


場所を指定すると次は右のようなダイアログが出るので、私は gae というフォルダ以下に gae 関連のプロジェクトを全部まとめておきたいので、真ん中のやつを選びました。これで gae というフォルダ以下に f1yosou というフォルダができて、そのファイルが中にチェックアウトされます。

するとどうでしょう。
お、Web プロジェクトで、GAE とさらに GWT も使ってることを検出してくれました。Configure を・・・

と思ってこのキャプチャをとっていたらこのポップアップは消えてしまいました!w でもしたの Event Log をクリックしたら同じメッセージとリンクがでていました。ナイスw
Configure をクリックするとこんなダイアログがでるので、OK。
すると File > Project Structure を表示して Facets を見ると、
のように定義されています。あとはここに SDK へのパスを入れたりすればよい。

・・・と思ったんですが、いろいろ問題が。そもそも Dev Server が起動しない(ブランクになる)とか。クラスパス関連がごしゃごしゃになってたりとか。そこでいろいろ苦労しながらなんとかできそうな状態に持っていったやり方を以下に書きます。

まずは新規に GAE/J + GWT のプロジェクトを作成します。File > New Project で Java Module を選択して Next。これで JDO を使う場合はその選択も忘れずに。これで空のプロジェクトができます。空ですがいろいろ設定されているのが大事。

Eclipse でプロジェクトを作った場合は恐らく web ディレクトリではなく war になっていると思うので、ここで web ディレクトリを war に Rename します。web の上で右クリック、Refactor > Rename で war にしましょう。この rename がなぜか反映されてないところがあるのでそこを修正します。プロジェクトを右クリックして Open Module Settings を開くと上にあるようなダイアログが開くので、Facets の Web を選んで、Web Resource Directory 名を変更します。

さていよいよもとのコードを移行します。VCS > Checkout from Version Control > Subversion で上記の作業をします。そのときのチェックアウト先を今作ったプロジェクトそのものにします(つまり上書きします)。そして VCS > Enable Version Control で Subversion を選びます。私の場合 jdoconfig.xml と appengine-web.xml、web.xml が青くなりました。つまりチェックインされているものが変更されているということですね。これらの変更を Revert しましょう。右クリックで Subversion > Revert で戻せます。あと不要な index.jsp も消します。

この状態だとライブラリはパスが通ってない状態なので、WEB-INF/lib に何か入れていた場合はこれらを追加しなければいけません。普通の Java のときと同様ですが右クリックして Add as Library で追加します。また Open Module Settings をして Artifacts の WEB-INF/lib のところに追加するのも忘れずに。

この状態で Run/Debug で AppEngine Dev サーバーを起動したところようやく起動できました。・・・できたんですけどブラウザには悲しいページが。

まだだ!くじけるな!

この話は(たぶん)IntelliJ IDEA 云々ではないようです。既に問題になっていたようで。なので解決方法は Run > Edit Configuration から開くダイアログの VM options に-XX:-UseSplitVerifier をつけるだけ。そしてサーバーを再起動すると・・・
やっとキター!(表示が変なのはデータがまだないからです。)

この勢いで GWT の起動構成も確認します。自分のモジュールの .gwt.xml を右クリックして Run/Debug 。VM Options が必要な場合は上と同様に入れます。そして起動、おりゃーっ!
orz

まあいろいろ起きるもんですね・・・。生みの苦しみかこれは。とはいえこれは簡単に直って、また起動構成に戻り、Server を Default から AppEngine Dev に切り替えて起動しなおすだけでした。ふー。

さあ後は deploy だな! Tools > Upload AppEngine Application を選ぶだけ!
java.lang.RuntimeException: The application contains Java 7 classes, but the --use_java7 flag has not been set.
Unable to update app: The application contains Java 7 classes, but the --use_java7 flag has not been set.
いじめか orz
きっと Java6 にすれば治るんでしょう。GAE って確かまだ Java7 は正式サポートじゃなかったような気がするし。いやもう眠いから調べないですけど。切り替え!もう一度 Upload!

で、できた・・・。

これで恐らく開発できる状態にまではたどり着けた、と思うのですが。しばらく使ってみて今後どうするか考えます。ちなみにこのやり方が正しいのかベストなのか等全く見当もつかないので、もし試す場合は自己責任でお願いします。

2013年4月24日水曜日

Heroku を試す(4)~アプリを作成

さていよいよアプリを作ってみましょう。プロジェクトを作成する画面に Create Heroku App from Template なるメニューがあるのでそれを選びます。

次の画面では・・・何を選びますかね。Getting Started には別にサンプルを作るところまで書かれているわけではないので何も指定はないようです。一番シンプルそうなのは・・・ Embedded Jetty-Servlet Application でしょうか。それを選んで適当に名前をつけて進み・・・ませんw

こんどはこんなエラーが。あれー、ちゃんとセットしたはずなんだけどな。
仕方ないので、前のステップに戻って、Create an SSH Key と Adding your ... のところをやってみます。その後もう一度作ろうとすると、今度は「その名前は既にあるぜー」と言われてしまいます。なので
C:\>heroku apps
=== My Apps
sdk0815-sample


C:\>heroku apps:destroy sdk0815-sample

 !    WARNING: Potentially Destructive Action
 !    This command will destroy sdk0815-sample (including all add-ons).
 !    To proceed, type "sdk0815-sample" or re-run this command with --confirm sdk0815-sample

> sdk0815-sample
Destroying sdk0815-sample (including all add-ons)... done
そして再挑戦すると・・・できたー!
って×出てるしw メッセージを見ると
maven-dependency-plugin (goals "copy-dependencies", "unpack") is not supported by m2e. pom.xml /sdk0815-sample line 48 Maven Project Build Lifecycle Mapping Problem
ふむ・・・。m2e は私が勝手に入れてたプラグインであって、別にここでは必須ではないですよね。ということはエラーが出てても大丈夫か?とりあえずこのまま進めーw

今この状態はどうなってるのか気になるので、Window -> Show View -> Other... で My Heroku Applications ビューを開きます。そこに出てきたアプリを右クリックして Open を選ぶと・・・
キター!

2013年4月16日火曜日

Heroku を試す(3)~ Eclipse を使って

ではこちらに従って Eclipse を使ってアプリケーションを作ってみます。
You can build/deploy and manage your Heroku applications right from within Eclipse using the Heroku Eclipse plugin.
とありますのでプラグインがあるんですね。要件は
ということで Eclipse 3.7 以上を用意しましょう。私は 4.2 で行きます。 更新サイトを追加してインストールするだけ。Eclipse を再起動します。

次はプリファレンスに移動して Email と Password を入れて Login を押せば・・・、あれ。

なぜかエラーが出てますね・・・。いろいろ調べてましたが最終的にはエラービューに行ってみたところ、
Secure storage was unable to retrieve the master password. If secure storage was created using a different Windows account, you'll have to switch back to that account. Alternatively, you can use the password recovery, or delete and re-create secure storage.
なるエラーが出ていました。うーむ。そもそもそのファイルがいつ作られたかも定かではないぐらいなので、消して再起動してみました。すると無事 Login を押したら API Key がセットされました。

次にその下にある Load SSH Key をクリックして、その1で作った .pub をロードします。これで準備完了かな?


2013年4月10日水曜日

Heroku を試す(2)~ Java を使う

さて私の専門(?)は Java なので Java のチュートリアルに進みます。ほかの言語のもたくさんありますね。Java はこちら。要件としては
  • Basic Java knowledge, including an installed version of the JVM and Maven 3.
  • Your application must run on the OpenJDK version 6, or 7 (8 is also available in beta).
  • A Heroku user account. Signup is free and instant.
ふむ。とりあえず Java の知識は当たり前として Maven もこの前いじりましたね。ほんの少しで恐縮ですがw OpenJDK で動くものでないといけないと。アカウントはついこの前作りました。というわけで準備はOK。

さて早速・・・と思ったら
If you’re an Eclipse user you can skip these steps and get started inside of an Eclipse workspace. See Getting Started with Heroku & Eclipse.
Eclipse 用のやり方は別にあるんですね。せっかくなので手に入れた IntelliJ IDEA で行こうかと思ってたんですが、まずは勝手知ったる Eclipse で始めてみます。というわけでそちらのページに従って進めるとします。

2013年4月8日月曜日

Heroku を試す(1)~ Getting Started

#f1yosou のサイトにアクセスしたことのある方なら既に感じられてるかもしれませんが、Google App Engine 上で作っているサイトは結構アクセスしたときのレスポンスが悪いですよね。これはしばらくアクセスがないと Idle 状態になるためです。もちろんお金を払えばインスタンスを常時起動しておけるので早くなるわけですが、別にあのサイトで1円も稼いでないわけでそれはちょっと・・・。

というわけで、ほかの PaaS サービスはどうなのか興味がありまして。最近よく耳にする(気がする) Heroku を試してみます。それで備忘録的にここに手順を書いていきます。私は何事もやってみないと身につかないタイプなので、Getting Started を探しましょう。あ、ありました。ここですね。これに従って進めましょう。

まずは Sign Up から。Eメールアドレスを入れるとメールが届くので、そのリンク先でパスワードを設定するだけです。特に名前とか聞かれないんですね。ログインすると比較的素っ気無い感じのページにログインできます。なんかコマンドっぽい(本当にコマンドかも?)ものが出てるところがちょっと玄人っぽくていいかもw

次は Heroku Toolbelt というものをインストールします。これはなんだろう。
Foreman, an easy option for running your apps locally; and Git, the revision control system needed for pushing applications to Heroku.
とありますね。ということはアプリを管理するツールと git が入るんですね。そういや deploy するのに git を使うってありましたので Linux でやってみようかと思ったけど Windows 用の Toolbelt をダウンロードしてしまったのでとりあえず Windows でやってみます。ダウンロードした exe を起動するだけでするっと入ります。

次はログインですか。早速試してみましょう。
C:\>heroku login
Enter your Heroku credentials.
Email: ********@*****.***
Password (typing will be hidden):
Could not find an existing public key.
Would you like to generate one? [Yn] Y
Generating new SSH public key.
 !    Could not generate key: 'ssh-keygen' は、内部コマンドまたは外部コマンド、
 !    操作可能なプログラムまたはバッチ ファイルとして認識されていません。
あれれ失敗しますね。インストーラーのところで ssh も入れるってあったはずですが・・・。うーむ。仕方ない、とりあえず Cygwin のパスを通して進んでみます。
C:\>set PATH=C:\cygwin\bin;%PATH%

C:\>heroku login
Enter your Heroku credentials.
Email: ********@*****.***
Password (typing will be hidden):
Could not find an existing public key.
Would you like to generate one? [Yn] Y
Generating new SSH public key.
Uploading SSH public key C:/Users/*****/.ssh/id_rsa.pub... done
Authentication successful.
できました。既に key があればそれを使うのもできそうですね。

次はいよいよサンプルアプリを作成してみます。

2013年3月22日金曜日

GAE/J + JDO で Single Property Index を作らせない

表題のとおりですがようやくたどり着いたのでメモ。

サイト自体にも書いていますが、#f1yosou Google App Engine/Java (以下 GAE/J)を使っています。もともと3年前(もう3年になりますか・・・)にはじめたときには結構余裕だったのですが、Googleさんの緩やかな締め付けwで無料での利用部分がどんどん制限されてきて、最初のころにはタコなコードを書いていても余裕があったのですが、最近はかなり厳しくなってきています。これまでもそれなりに使用量を抑制しつつなんとかごまかしてきました。

そんな最近の #f1yosou サイトのもっとも厳しい項目は、Datastore Write Operations の項目です。これは文字通り Entity を Datastore に書き込むと消費するやつですね。これが特に #f1yosou タグのついたツイートを解析して結果を書き込む処理を経るとかなり消費されます。処理としては
  • 該当するツイートの保存
  • 同一の予想をしたツイートのカウントを行い、その結果を保存
ということをしていますが、どうも後者の処理がかなりの書き込みを生じているようです。そもそもこの Datastore Write とは Entity を1つ書き込むと1回なのか?というところから調べ始めたところ、以下の記事がよくまとまっておりました。
EntityのPropetryの構成よって、Datastore writeの数は変わる!
なるほど。そもそもプロパティの数によって増えるのもあるんですがそれは実際に値をしまってるので仕方ないとして、各プロパティについて勝手に自動的に作成される Index の書き込みのほうが問題ですね。そもそも使ってないのに昇順・降順で2つ作られてるみたいですし。これを削減できればだいぶ効きそうです。ただし
Single Property Indexを作らないとComposite Indexも作成されない?
という考慮点もあるみたいなのでなんでもかんでも削れるわけではないようです。

と、ここまできて JDO ではどうやって指定するんだろう・・・と思って調べてもなかなかでてきません。いろいろググっていたらようやく Entity#setUnindexedProperty() なるものがでてきました。しかしこれも Low Level API。。。

まあそれでもいいか、と思ってやり方を探っていたらとうとう発見しました。まんまの質問がありましたw なぜこれに最初に行き当たらなかったのか不思議なぐらいそのままです。要するに
@Extension(vendorName = "datanucleus", key = "gae.unindexed", value="true")
を索引がいらないプロパティにつけるだけです。あら簡単。

早速実験してみます。1回処理すると以下のようになる Entity を用意しました。
 このクラス定義のところにある correct というプロパティに Index を作らないようにします。
 @Persistent
 @Extension(vendorName = "datanucleus", key = "gae.unindexed", value="true")
 private Boolean correct;
とすると、
のように2減りました。この2というのが昇順と降順で1つずつの結果のようです。
#上では赤丸がついている Entity にのみ処理をしました。

これで削減できるかな?

2013年3月18日月曜日

Eclipse + Maven その2

続きです。これだけでも十分便利なんですが、よくできてんなと思ったところをもう少し。今回想定しているのは前回作ったプロジェクトで Selenium を使ったコードを書いて隠蔽し、それを別のプロジェクトから利用するというシナリオです。

まず sample1 の App クラスを変更しておきます(別に main のままでもできますが、雰囲気を出すために)。そして後述する実験のために一度 sample1 を install しておきます。sample1 の pom.xml を右クリックして、Run As -> Maven install... を実行します。
 sample1 と同じように sample2 プロジェクトも作ります。
で、pom.xml を開き、dependency のところで sample1 を追加します。
すると
のようになります。アイコンでわかるとおりプロジェクト参照になってます。なので普通に sample1 のクラスが使えるので
とやって実行しただけでブラウザが上がってきます。

これだけでも十分便利なんですが、よくできてんなと思ったのはこの先です。さきほどプロジェクト参照になってると書きましたので、sample1 の App のほうを

のように変更して sample2 の Main を実行すると
と Yahoo! が開きます。ここで sample1 を閉じます。
すると先ほどプロジェクト参照になっていたものが最初にインストールしたほうに自動的に変更されます。
なので実行すればちゃんと動作しますが、開くのは Google のほうです。つまり、インストールされていればその依存を書くだけで使えますが、プロジェクトがあればそちらのコード変更を即座に反映した開発が可能ということです。これは便利ですね。

2013年3月16日土曜日

Eclipse + Maven その1

ひょんなことから Selenium を使う機会がありまして。それ自体はいいんですが前提のライブラリが多いこと多いこと・・・。これをマネージするのは正直つらそう。そう思いましてせっかくなので Maven を使ってみました。これは便利ですね。なので備忘録をかねて少々ご紹介。

まずは m2e を入れておきます。するとプロジェクトを作成するときに Maven Project が選べるようになります。
  先へ進んで最後に Group Id と Artifact ID を入れると


こんな感じにプロジェクトが作成されます。
左上に「M」がついてるので Maven 用に構成されたプロジェクトであることがわかります。pom.xml も作成されているので開くとエディターが開きます。
今回は Selenium を使いたいので依存関係を定義します。Dependencies のタブを開いて Add をクリックします。ダイアログが開くので、フィルターのところに selenium-java と入力して selenium-java を選んで

追加します。すると

このように自動的に classpath にも追加されます。こうなれば

のようにコードを書いて実行すると
 と動くわけです。