既存のHubotアプリケーションをOpenShiftで動かすまで

はじめに

HerokuでHubotを動かしていましたが、新しい料金プランの通知が来たので、他のクラウドサービスでも動かせるように出来ないかと思い、OpenShiftでやってみることにしました。

ただ、OpenShiftもDockerとKubernetesに対応したものに変わるということもあるので、それまでの経過措置です。

小さいインスタンスを24時間起動してても無料なサービスというのは、やはり儲からないのでしょうね。

参考にしたのは、Hitchhiker’s Guide to Tweetbots: Hosting a Hubot on OpenShift です。

OpenShiftへの登録

以下のサイトに登録の方法があるので、参考にしてください。

一旦、webの画面でサンプルアプリケーションとかを作って動かしておくと、今後の操作とかで省略出来る箇所もあるので、試しておくのをお勧めします。

rhcのインストール

登録が済んだら、コマンドラインツールが提供されているので、インストールします。

次にアカウントの情報を登録します。

公開鍵とドメインの設定をする必要がありますが、こちらもWebの画面でやっておくことをお勧めします。

Hubotアプリケーションの修正

参考にするのは、こちらです。

修正とは言っても、以下の2点です。

  • プロジェクトに .openshift/markers/use_npm という空のファイルを作る。
  • package.jsonに以下のようなHubot起動用のコマンドを追加する。
"scripts": {
"start": "PORT=$OPENSHIFT_NODEJS_PORT BIND_ADDRESS=$OPENSHIFT_NODEJS_IP HEROKU_URL=$OPENSHIFT_APP_DNS REDIS_URL=redis://:$REDIS_PASSWORD@$OPENSHIFT_REDIS_HOST:$OPENSHIFT_REDIS_PORT bin/hubot -n Hubot -a shell"
}

以下の3つの変数については、OpenShiftから提供されます。

  • OPENSHIFT_NODEJS_PORT
  • OPENSHIFT_NODEJS_IP
  • OPENSHIFT_APP_DNS

詳細は、Informational Environment Variables を参考にしてください。

redisに関しては、上記のサイトで利用しているcartridgeを使う場合と、https://marketplace.openshift.com/home で提供されているredis cloudを使う場合があります。

私の場合、redis cloudを使う選択をしたので、設定する必要があります。 アプリケーションに変数を設定するには先程インストールしたコマンドラインツールを利用します。

$ rhc env set OPENSHIFT_REDIS_HOST=<redisホスト名>
$ rhc env set OPENSHIFT_REDIS_PORT=<ポート>
$ rhc env set REDIS_PASSWORD=<パスワード>

hubot brainを使っていなかったので、データを移行する必要がありませんでした。 必要であれば、上記のサイトを参考に移行してください。

Hubotとslackと連携している場合は、以下の様に変数を設定してください。

$ rhc env set HUBOT_SLACK_TOKEN=<トークン>

Travis CIでデプロイ

OpenShiftはtravis CIでデプロイ出来るので、以下の様に設定します。

language: node_js
node_js:
  - "0.10"
deploy:
  provider: openshift
  user: $OPENSHIFT_USERNAME
  password: $OPENSHIFT_PASSWORD
  app: $OPENSHIFT_APP_NAME
  domain: $OPENSHIFT_APP_NAMESPACE

ユーザ名とパスワードをtravisに設定するところが気になるところですが、OpenShiftにデプロイ用のトークン機能が無いので仕方ありません。

設定方法は、Using Settings を参考にしてください。

上記の OPENSHIFT_APP_NAMESPACE ですが、ドメイン名を設定します。

最後に

単純な移行だけなら、上記の設定をしてgit pushのremoteを変更するだけでなんとかなります。

もしHubotでスケジューリングしている様な場合は、単純に移行してしまうとタイムゾーンの関係でズレてしまうと思います。

私自身、OpenShift上のNode.jsアプリケーションでタイムゾーンを変更する方法が分からないので、変更する方法を知っている方がいらっしゃったら、教えて頂けると助かります。

本格的にHeroku上でHubotを使っている場合、素直にHobbyプランまたはそれ以上に移行するのがいいと思います。

追記 2015-05-11

OpenShiftも48時間でアイドリングするので、@bouzuya さんの解決策を採用させていただくことにしました。

追記 2015-05-17

OpenShiftでのタイムゾーンの変更ですが、@nekop さんに教えて頂きました。ありがとうございます。

プロジェクトに .openshift/action_hooks/pre_start_nodejs を作ります。

内容は、以下の通りで変えることが出来ました。

#!/bin/bash

echo "Execute pre_restart nodejs hook"

export TZ='Asia/Tokyo'

echo "$TZ"
echo `date`

TinkererでOpen Graph Protocol(OGP)を使う

はじめに

Open Graph Protocol(OGP)

これだけは知っておきたいOGP (Open Graph Protocol)

http://nex.fm/ogp/

前から気になっていたのですが、このブログで使っている Tinkerer でのやり方が分からなかったので、放置してましたが、対応していた方がいらっしゃったので、試してみました。

このブログにOGPを設定した

http://misc.mat2uken.net/blog/2013/05/31/setting_ogp.html

やりかた

こちらを参考にしながらやってみました。

Tinkererでは、layout.htmlを作ることで、全体に対応した既存のテンプレートを拡張出来るみたいです。

_templatesディレクトリを作る

プロジェクト直下に _templates ディレクトリを作成します。

私の場合、既にはてブボタンや、twitterのボタンを追加する為に作っていました。

_templates/layout.htmlを作る

layout.htmlは作っていなかったので、以下のコードを記載して追加しました。

{% extends "!layout.html" %}

{% block extrahead %}

<meta property="og:title" content="{{ shorttitle }}" />
<meta property="og:description" content="{{ title|striptags|e }}" />
<meta property="og:url" content="http://grimrose.bitbucket.org/blog/html/{{ pagename }}{{ file_suffix }}" />
<meta property="og:image" content="http://grimrose.bitbucket.org/blog/html/_static/ogp_image_400x400.jpeg" />

{% endblock %}

index.htmlにも追加する

プロジェクト直下のindex.htmlにも設定しておくと、いいと思います。

今回は、以下のタグを追加しました。

<meta property="og:title" content="grimrose's tech log" />
<meta property="og:description" content="ホーム" />
<meta property="og:url" content="http://grimrose.bitbucket.org/" />
<meta property="og:image" content="http://grimrose.bitbucket.org/blog/html/_static/ogp_image_400x400.jpeg" />

Open Graph Object Debuggerで確認する

後は、buildして、pushして、確認します。

Open Graph Object Debugger

https://developers.facebook.com/tools/debug/og/object/

自分のブログの記事のURLを入れてください。

When shared, this is what will be included の箇所に表示されます。

間違いがあったりすると、いろいろ指摘されます。

まとめ

Tinkererは、あれこれやりたいなと思った時に拡張するためのポイントが最小限になっているのが、ありがたいですね。

Ratpackについて(延長戦)

はじめに

G*Advent Calendar(Groovy,Grails,Gradle,Spock...) Advent Calendar 2014Ratpack についての紹介をしました。

テスティングフレームワークや、CircleCI、Heroku buttonについての紹介もしてみたいと思います。

Ratpackのテスティングフレームワーク

http://www.ratpack.io/manual/current/testing.html

http://www.ratpack.io/manual/current/groovy.html#testing

Ratpackには、UnitTest, GroovyUnitTest, ApplicationUnderTest のようにテスト用のヘルパークラスが用意されています。

使い方は、TestHttpClient を参考にしてください。

テストヘルパーを組み合わせる事で、定型的なセットアップも簡単に記述することが出来ます。

また、Geb と組み合わることで簡単に Selenium WebDriver を使ったテストを書くことが出来ます。

RemoteControlModule を使うと Groovy Remote Control を呼ぶことが出来るので、テストに必要なデータなどを予め登録することが出来ます。

CircleCI

https://circleci.com/

最近では、CIのサービスが増えており、Travis CI 以外の選択肢も選べるようになってきました。

Ratpack本体は、ビルドパイプラインが特徴的な Snap CI を利用しているみたいです。

publicなレポジトリでも利用できるようになったCircleCIが注目されているので、Ratpackで使える設定をしてみます。

その他のGradleを使ったWebアプリケーションのプロジェクトにも応用できると思います。

まず、GitHubのレポジトリの SettingsWebhooks & Services を選びます。

次に、Add Service から CircleCI を追加します。

circle.ymlが無くてもCircleCI側でいろいろ空気を読んでくれますが、Ratpackでは、Java8とGradle2.xを使う関係上、circle.ymlを追加する必要があります。

circle.ymlの書き方は、 Sample circle.yml file を参考にしてください。

以下の様にすると、postgresqlでのテスト、Herokuへのdeployが出来るようになります。

Herokuへdeployする為には、予めCircleCIの Project Settings から Continuous Deployment のHerokuにてデプロイする為の設定を行う必要があります。

machine:
  java:
    version: oraclejdk8
  timezone:
    Asia/Tokyo
  environment:
    DATABASE_URL: postgres://ubuntu:@127.0.0.1:5432/circle_test

dependencies:
  override:
    - ./gradlew dependencies

  cache_directories:
    - "~/.gradle"

test:
  override:
    - ./gradlew test

deployment:
  staging:
    branch: master
      heroku:
      appname: foo-bar-123

Heroku buttonについて

Creating a ‘Deploy to Heroku’ Button

Herokuには、自分のレポジトリのコードを他の人がHeroku上で利用できるようにする Heroku Button を提供する機能があります。

折角なので、今回のサンプルプロジェクトを対応させてみます。

手順は、以下の通りです。

  • app.json ファイルをプロジェクトの直下に設置する。
  • READMEにボタンを設置する。

app.jsonの内容については、app.json Schema を参考にしてください。

とはいえ、人の手で書いていくには少し骨が折れる作業なので、app.json を利用して作ってしまいましょう。

app.jsonを使うにはnode.jsをインストールしておく必要があります。

あと、herokuのgitの設定によっては失敗するかもしれません。 その際は、.git/config のherokuのurlを確認してください。必要に応じて修正する必要があります。

READMEには、以下の様にするとボタンを設置する事が出来ます。

ボタンは、こんな感じです。

Deploy

まとめ

以前に比べてアプリケーションを動かす環境やCIと連携できるサービスが簡単になってきました。

Gradleやモダンなフレームワークを利用することで、JavaやGroovyでもアプリケーションサーバを用意せずに使えたり、組み込みにすることでポータビリティを上げられています。

Ratpack以外にも、JavaやGroovyのWebアプリケーションをHerokuへのデプロイやCIサービスとの連携が出来ると思いますので、試してみてはいかがでしょうか。

Ratpackについて(後編)

はじめに

この記事は、G*Advent Calendar(Groovy,Grails,Gradle,Spock...) Advent Calendar 2014 の7日目として書かれたものです。

6日目は @grimrose さんの Ratpackについて(前編) です。

8日目は、@nobusue さんの Gradle Groovy Shellプラグインを使って依存ライブラリ込みのREPLを起動する #gadvent です。

Ratpackプロジェクトの作り方

Ratpackは、lazybones を使うと簡単にプロジェクトを作る事が出来ます。

lazybonesは GVM からインストールすることが出来ます。

$ gvm install lazybones

lazybonesからRatpackのプロジェクトを作る場合、無印とliteが選べますが、今回はmoduleを作りますので無印で行います。

liteの方は、クラスやテストのディレクトリが無いシンプルな構造をしています。目的にあわせてプロジェクトを作る事が出来ますので、Hello Worldを試したい場合は、liteで作ってみてはいかがでしょうか。

以下のコマンドを実行すると、その場所にプロジェクトが出来ます。

$ mkdir sample
$ cd sample
$ lazybones create ratpack .

lasybonesには、プロジェクト作成時のオプションがあるので、lazybones create だけ実行して確認してください。

IntelliJ IDEAかEclipseで取り込む前に、GradleでIDEのプロジェクトファイルを作っておきましょう。

$ gradle idea
## or
$ gradle eclipse

springloadedについて

2014年12月現在、標準でspringloadedが適用されていますが、http://forum.ratpack.io/springloaded-error-td681.html を見る限り、うまく動作しない模様なので、コメントアウトしておくのをおすすめします。

ディレクトリ構成について

Ratpackは以下の様なディレクトリの構成を取ります。

特徴的なのはratpackディレクトリです。このディレクトリの中に静的なファイルやratpack.groovyを置きます。

<proj>
  |
  +- src
      |
      +- ratpack
      |     |
      |     +- ratpack.groovy
      |     +- ratpack.properties
      |     +- public          // 静的なファイル等のassets
      |          |
      |          +- images
      |          +- lib
      |          +- scripts
      |          +- styles
      |
      +- main
      |   |
      |   +- groovy
              |
              +- // アプリケーションのクラス
      |
      +- test
          |
          +- groovy
              |
              +- // Spock のテスト

起動と停止

起動する場合は、以下のコマンドで出来ます。

$ gradle run

起動すると、デフォルトでは localhost:5050 で待ち受けているので、ブラウザでアクセスしましょう。

停止は、Ctrl + Cで出来ます。

お題

今回は、メッセージの登録と表示のWebアプリケーションを作ってみます。

View

lazybonesで作ったプロジェクトのテンプレートエンジンは、GroovyTemplateなのでそのまま使います。

GroovyTemplateは、拡張子が任意なので、HTMLをそのままテンプレートとして扱う事が出来ます。

また、The MarkupTemplateEngine を使うとGroovyを使ってより柔軟にレイアウトを記載できます。

今回は、一つのページで登録と一覧を行い、一覧は、JSON APIを呼んで表示するようにしてみたいと思います。

ルーティング(Routes)

ratpack.groovy のルーティングに関する箇所、以下の通りです。

handlers {
  get {
    render groovyTemplate("index.html", title: "Message App")
  }

  handler('messages') {
    byMethod {
      get {
        redirect '/' // index.htmlへリダイレクト
      }
      post {
        // メッセージを登録する。
      }
    }
  }

  delete('messages/:id') {
    // メッセージを削除する。
  }

  handler('api') {
    // メッセージの一覧をJSONで返す。
  }

  assets "public"
}

Moduleについて

今回用意するモジュールは、以下の通りです。

  • SQL
  • HikariCP
  • RxJava
  • Jackson
  • テンプレート
  • 今回作成するメッセージに関するモジュール

それぞれを bindings ブロックにて登録します。

bindings {
  add TemplatingModule

  add(HikariModule) { HikariConfig config ->
    config.driverClassName = 'org.postgresql.Driver'

    // Herokuとローカルをここで切り替える
    def uri = new URI(System.env.DATABASE_URL ?: "postgres://test:test@localhost/gadvent2014")

    def url = "jdbc:postgresql://${uri.host}${uri.path}"
    username = uri.userInfo.split(":")[0]
    password = uri.userInfo.split(":")[1]

    config.jdbcUrl = url
    config.username = username
    config.password = password
  }
  add new SqlModule()
  add new JacksonModule()

  // 今回作成するメッセージに関するモジュール
  add new MessageModule()

  init { MessageService messageService ->
    RxRatpack.initialize()
    messageService.init()
  }
}

アプリケーション

今回作成したのは以下のクラスです。

import groovy.transform.Canonical

@Canonical
class Message {
  Long id
  Date createAt
  String contents
}

import com.google.inject.AbstractModule
import com.google.inject.Scopes

class MessageModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(MessageRepository).in(Scopes.SINGLETON)
    bind(MessageService).in(Scopes.SINGLETON)
  }

}

import com.google.inject.Inject
import groovy.sql.Sql
import groovy.util.logging.Slf4j
import rx.Observable

import java.sql.Timestamp

@Slf4j
class MessageRepository {

  @Inject
  private Sql sql

  void initialize() {
    log.info "Creating tables"
    sql.executeUpdate("DROP TABLE IF EXISTS messages")
    sql.executeUpdate("CREATE TABLE IF NOT EXISTS messages (id SERIAL PRIMARY KEY, createAt TIMESTAMP, contents TEXT)")
  }

  Observable<List<Message>> findAll() {
    Observable.from(sql.rows("SELECT id, createAt, contents FROM messages ORDER BY createAt")).map {
    new Message(id: it.id, createAt: it.createAt, contents: it.contents)
    }.toList()
  }

  def insert(Message message) {
    sql.executeInsert("INSERT INTO messages (createAt, contents) VALUES (?, ?)", new Timestamp(message.createAt.getTime()), message.contents)
  }

  def delete(long id) {
    sql.executeUpdate("DELETE FROM messages WHERE id = ?", id)
  }

}

import com.google.inject.Inject
import groovy.util.logging.Slf4j

@Slf4j
class MessageService {

  @Inject
  MessageRepository repository

  void init() {
    repository.initialize()
  }

  def all() {
    repository.findAll()
  }

  def create(String contents) {
    Message message = new Message(createAt: new Date(), contents: contents)
    repository.insert(message)
  }

  def delete(long id) {
    repository.delete(id)
  }

}

これらのクラスを ratpack.groovy から利用します。

handlers { MessageService messageService ->
  get {
    render groovyTemplate("index.html",
      title: "Message App"
    )
  }

  handler('messages') {
    byMethod {
      get {
        redirect '/'
      }
      post {
        // メッセージを登録する。
        Form form = parse(Form)
        def contents = form.get('contents', '')
        if (!contents) {
          render groovyTemplate('index.html',
            title: "Message App",
            errorMessage: 'メッセージを入力してください'
          )
        } else {
          context.blocking {
            messageService.create(contents)
          }.then {
            redirect '/'
          }
        }
      }
    }
  }

  delete('messages/:id') {
    // メッセージを削除する。
    def id = pathTokens["id"].toLong()
    context.blocking {
      messageService.delete(id)
    }.then {
      render Jackson.json('success')
    }
  }

  handler('api') {
    // メッセージの一覧をJSONで返す。
    messageService.all().subscribe { List<Message> messages ->
      render Jackson.json(messages)
    }
  }

  assets "public"
}

今回作成したアプリケーションのソースは、こちらに公開しています。

https://github.com/grimrose/gadvent2014

herokuへのデプロイ

あらかじめHerokuのアカウントを登録しておきます。

以下のコマンドでログイン出来る事を確認してください。

$ heroku login

RatpackはJava8のJVMで動かす必要があるので、system.properties には、以下の様に記載します。

java.runtime.version=1.8

Ratpackのプロジェクト名によってHerokuでの設定値が利用されるので、プロジェクト名を setting.gradle に指定します。

rootProject.name = "«project name»"

Ratpackはアプリケーションのポートを 5050 をデフォルトとして利用しますが、Herokuは指定されたポートで動かす必要がありますので、Prockfile には以下の様に記載します。

また、アプリケーション固有の設定をプロジェクト名を大文字にした «PROJECT_NAME»_OPTS として設定することが出来ます。 例えば、g-advent-2014 といったプロジェクト名であれば、G_ADVENT_2014 といった様に定義されます。

web: env "«PROJECT_NAME»_OPTS=-Dratpack.port=$PORT" build/install/«project name»/bin/«project name»

ここで作成した、system.properties, setting.gradle, Procfile をコミットしたら、準備完了です。

JavaのWebアプリケーションをHerokuで動かすには、buildpack が必要になります。

Ratpackは特殊なbuildpackではなく、Gradleのbuildpackを使用します。

以下のコマンドで、Herokuに新規アプリケーションを作成します。

$ heroku create --buildpack https://github.com/heroku/heroku-buildpack-gradle

今回のアプリケーションでは、RDBMSとしてPostgreSQLを使いますので、Herokuのアドオンを追加します。

$ heroku addons:add heroku-postgresql

以下のコマンドを実行して、Herokuにpushしましょう。

$ git push heroku master

最後に、以下のコマンドで始めることが出来ます。

$ heroku open

まとめ

Ratpackは、小さなWebアプリケーションを作るのに向いているので、モジュールを組み合わせて大きくしていくのに向いてます。 また、NettyをベースにしているためWebSocketアプリケーションが作れます。

但し、いいところばかりでは無く、日本語の情報やドキュメントも不十分な箇所もあります。

また、非同期処理について知識が無いと、テストやデバッグでハマってしまったり、ブロックしてしまうコードを書いてパフォーマンスが出ないといったこともありえます。

既存のServletベースのアプリケーションでは物足りなかったり、他のNettyベースのフレームワークとは一味違った開発をしてみたいチャレンジャーな人は、試してみてはいかがでしょうか。

Ratpackについて(前編)

はじめに

この記事は、G*Advent Calendar(Groovy,Grails,Gradle,Spock...) Advent Calendar 2014 の6日目として書かれたものです。

5日目は @kyon_mm さんの Geb 0.10の新機能紹介 #gadvent です。

7日目は @grimrose さんの Ratpackについて(後編) です。

Ratpackとは

http://www.ratpack.io/

Ratpackは、NettyをベースとしたJava8とGroovyで書かれたWebアプリケーションフレームワークです。

アプリケーションもまた、Java8またはGroovyで記述出来ます。

フルスタックなフレームワークではなく所謂、MicroWebフレームワークとか軽量Webフレームワークとか呼ばれるカテゴリに属しています。

一番の特徴としては、Nettyをベースにしていることもあるので、Asynchronous & Non Blocking です。

JavaでWebアプリケーションフレームワークというと、ServletやFilterをラップしたフレームワークが多いですが、その場合、別途GlassfishやTomcat, Jettyといったアプリケーションサーバが必要です。

もちろん組み込み可能なアプリケーションサーバを内蔵してwarファイルから起動というようなことも出来ます。

そういった従来のServlet前提のWebアプリケーションとは違い、Ratpackはアプリケーションサーバを必要としません。

fat-jarやZipで固めてデプロイ出来るフレームワークなので、Dockerなどのコンテナと相性が抜群です。

他のWAFとの違い

http://www.ratpack.io/manual/current/intro.html#compared_to

Ratpackから見た他のWebアプリケーションフレームワークとの違いは、以下のような内容です。

Netty

http://netty.io

Nettyは、Ratpackのベースとなっているように、低位のレイヤーをサポートしてるライブラリです。 HTTP以外のプロトコルもサポートしているため、NettyをベースにしたフレームワークはRatpack以外にも様々存在します。

RatpackはNettyをベースとしていますが、オーバーヘッドになるような処理は加えておらず、パフォーマンスはNettyと遜色ありません。

パフォーマンスを優先したいような場合は、NettyのAPIにアクセス出来るようになっています。

Vert.x

http://vertx.io

Vert.xは、個人的に好きなフレームワークで、Ratpackと同じくNettyをベースとしています。

各モジュールがJSONをメッセージバスを介してやりとりを行うようなアプリケーションコンテナとしての性格が強く、言語もJavaやGroovy以外のJVM上で動作できるものを組み合わせて扱うことが出来るようになっています。

また、非同期の処理を行う手段として、コールバックを採用しました。

Ratpackは、よりHTTPに特化しており、Vert.xのWebアプリケーションフレームワークである Yoke に似てます。また、非同期処理の手段は、Vert.xと違い、所謂 Promise を基調とした処理を採用しています。

RxNetty

https://github.com/Netflix/RxNetty

RxNettyは、RxJavaを使い、NettyのAPIをよりリアクティブにしたものです。

Grails

http://grails.org

言わずと知れたGroovyのフルスタックなWebアプリケーションフレームワークです。

Servletをベースとし、SpringFramework, Groovyを採用したフレームワークで、様々なプラグインを組み合わせることで多機能なアプリケーションを作ることが出来ます。

Spark

http://www.sparkjava.com

並列データ処理フレームワークである Apache Spark ではなく、Sinatraに影響を受けたMicroWebフレームワークです。

Servletをベースとしていますが、Servlet APIを意識させないようなコードを書かせるようなフレームワークです。

また、Java8のlambda式を使うことで、より短く簡潔に書けるようになっています。

組み込みアプリケーションサーバのJettyを採用しているので、fat-jarでデプロイすることが出来ます。

Dropwizard

https://dropwizard.github.io/dropwizard

RatpackのページではTBD扱いされていますが、2014年注目されたWebアプリケーションフレームワークの一つです。

Javaでは定番のライブラリを採用したフルスタックなフレームワークです。

組み込みアプリケーションサーバを内蔵し、fat-jarでデプロイ可能というコンセプトは、Twelve-Factor App に基いており、Immutable Infrastructureと相性が良く、そのアイデアの素晴らしさからか、Springframeworkへかなり影響を与え、SpringBootがリリースされたのは記憶に新しいところです。

アーキテクチャ

Ratpackは, MVC2で言われる所謂コントローラー層としての機能を担当しています。

ratpack.handling.Context とそれを扱う ratpack.handling.Handler が主なInterfaceです。

Handlerは所謂FunctionalInterfaceなので、lambda式で書くことが出来ます。

ビュー層は、以下のテンプレートエンジンであれば、モジュールが用意されています。

  • handlebars
  • thymeleaf
  • Groovy Template

APIとして使う場合にも、JacksonやGroovyのJSONのモジュールが用意されています。

モデル層は、特定のものが用意されている訳ではありませんが、Ratpackが用意しているモジュールにはH2、HikariCPといったものがあるので利用できます。 もちろんGroovyが使えるので、GroovyのSQLに関する機能も使えます。

DIコンテナとしてGuiceが用意されているので、モジュールを作ればモデル層や他のテンプレートエンジン等を使うことが出来ます。

モデル層で注意しなければならないのは、Nettyがイベント駆動のエンジンであることから、イベントループをblockする コード、例えばDBにアクセスするコード等です。

但し、Ratpackでは、blockするような場合は、明示的に Context#blocking(Callable) を使うことで対応できます。

また、Context#promise(Action<Fulfiller<T>>) を使うことで、同期的な処理をすることが出来ます。

HTTPのリクエストやレスポンスは、Contextから取得する事で利用できます。

こういったHandlerの処理を src/ratpack/ratpack.groovy に記載していきます。

Groovyの場合は、以下のように記載していきます。

import static ratpack.groovy.Groovy.ratpack

ratpack {
  handlers {
    get {
      render "Hello world!"
    }

    get('foo')  {
      render "Foooooooo!"
    }

  }
}

後編へつづく

次回は、実際にRatpackを使ったWebアプリケーションを作ってHerokuへ公開するまでを紹介してみたいと思います。

RxJava Night でVert.xについて話してきました #rxjnight

RxJava Night #rxjnight

http://connpass.com/event/9061/

はじめに

RxJavaは、あまり使ったことは無いのですが、Vert.xに mod-rxvertx があったり、 @muraken720 さんの RxJavaを使ってCallback Hellから脱出する( Vert.x がいいね!第5回 ) の記事を見て興味があったので、3.0に向けていろいろと動き出している事と、気になっていた Reactive Streams と併せて話してみたいと思ってたので、参加しました。

資料

Vert.xからみたReactive Streams

http://www.grimrose.org/RxJavaNight2014/

MDwiki

Markdownをスライド代わりに使うことがあったのですが、もう少し凝ったことをしてみたいと思ってたので、MDwiki を使ってみました。

他の方のスライドを紹介したかったので、iframeを埋め込んだり出来たのは良かったです。

本来であればWikiに使うのが正しいと思いますが、MDwiki example websites を見る限りいろいろと応用が出来そうです。

感想

参加者の多くは、Androidを使ってる人のようでした。 ReactiveX/RxAndroid の話もありましたし、AndroidでCallbackを書くのはつらそうなので、そういった意味でも注目されていたようです。

サーバーサイドの方が少なかったのは、RxJavaを実際に使ってる人が少ない上に、あえて使うような状況に遭遇しにくいからではないかと思いました。 Java8と組み合わせることでかなりすっきりと書けるので、Java8という選択肢がない現場では興味の対象となりにくいのかもしれないと感じました。

とはいえ、Netflix の様にJavaまたはJVMで動作する言語でサーバーサイドを書いていますし、Rx本家のC#もゲームサービスのバックエンドに使われているので、今後はそういったお話が出てくるが楽しみです。

今回は、Rxの歴史を知ることが出来たのが一番興味深かったです。

懇親会では、Rxの考え方とかテストはどうしたらいいのか等をお伺いすることが出来たので試してみたいと思います。

Vert.xについては、3.0に向けていろいろ情報収集をしつつ、触っていければと思います。

主催者の @hotchemi さん、発表者の皆さん、会場を提供して下さったPixivさん、ありがとうございました。

テンプレートエンジンNightでGroovy Templateの紹介をしてきました #tenight

はじめに

テンプレートエンジンNight

http://www.zusaar.com/event/10707003

Groovyには、テンプレートエンジンが標準で仕様に入っているので、紹介してきました。

補足

  • Simple Template Engineは、以下のように使います。

    import groovy.text.SimpleTemplateEngine
    
    def text = 'Hello "$placeHolder"!'
    def binding = ["placeHolder":"Groovy"]
    
    def engine = new SimpleTemplateEngine()
    template = engine.createTemplate(text).make(binding)
    
    assert 'Hello "Groovy"!' == template.toString()
    
  • Simple Template Engineの詳細な使い方はこちらです。

    G*Magazine Vol.6 オレオレ・プログラミング GROOVY

    http://beta.mybetabook.com/showpage/51053be10cf2ffb79bb047f0

  • GroovyのテンプレートエンジンはJavaからでも利用することが出来ます。

    例えば、Markup Template Engineを使う場合は、以下のとおりです。

    try (StringWriter writer = new StringWriter()) {
        TemplateConfiguration config = new TemplateConfiguration();
        MarkupTemplateEngine engine = new MarkupTemplateEngine(config);
        // createTemplateにはStringの他にReader, URLを渡せます
        Template template = engine.createTemplate("p('test template')");
        Map<String, Object> model = new HashMap<>();
        Writable output = template.make(model);
        // java.io.Writerを継承したインスタンスを渡してください
        output.writeTo(writer);
        System.out.println(writer);
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
    
  • Groovyのテンプレートエンジンの機能についての詳細は、こちらです。

    Template engines

    http://groovy-lang.org/templating.html

  • JsonBuilderは、以下の様にClosureを使って書くことが出来ます。

    import groovy.json.*
    
    def json = new JsonBuilder()
    json {
        message {
            text "Hello Groovy!"
        }
    }
    println json
    // 整形して出力することも出来ます
    println json.toPrettyString()
    
    {"message":{"text":"Hello Groovy!"}}
    {
        "message": {
            "text": "Hello Groovy!"
        }
    }
    

    JsonBuilderのサンプルはこちらです。

    http://groovyconsole.appspot.com/script/498001

    GroovyにはJSONのParserもあります。

    http://groovy-lang.org/json.html

  • スライドで紹介したGroovy Template を利用しているプロダクトはこちらです。

Groovyには、テンプレートエンジン以外にもJavaから使える機能が沢山あります。

また、Gradle は2.0からであればGroovy2.3の機能を使えるので、試してみてはいかがでしょうか。

感想

JVM以外のテンプレートエンジンのお話も聞けて、当日はとても楽しかったです。

当日は、JavaというかJVMのエンジニアが少なく、PHP, Perl, Rubyの方が多い印象でした。

Webデザイナーさんとの協業を考えると、HTMLのDOMにどうアプローチするのかを考えないと、お互いの為にならないということを知りました。

その他にも、JVM以外のテンプレートエンジンでの苦労話を聞いて、かなり勉強になりました。

Groovyを知ってたり使ってらっしゃる方が多かったのは、個人的には意外でした。

やはり、AndroidでGradleが採用されたから使っているというのが大きいのではないかと思います。

あと、Pixivさんのオフィスに初めてお邪魔して、楽しそうだなぁと思いました。

Smarty2で苦労されていらっしゃるみたいですが、良い解決策が見つかる事を願ってます。

主催者の @moznion さん、発表者の皆さん、会場を提供して下さったPixivさん、ありがとうございました。

また別のNightでお会いしましょう。

Gradle plugin を公開してみよう

Gradle plugin portal

http://plugins.gradle.org/

ついに、待望のGradleのPluginを管理するシステムが動き出し始めました。

これで、GradleのPluginを探しまわらなくても、公開しても自分しか使ってない寂しい思いをしなくても良くなります。

GradleのPluginの作り方は、 Chapter 58. Writing Custom Plugins第58章 カスタムプラグインの作成 を参考にしてください。

公開するための手順

注意: 2014-07-22現在の手順なので、変更されている場合があります。

http://plugins.gradle.org/submit

1. Gradle Plugin ID

以前から自分が使うために作っていたGradle Pluginを公開してみようと思いましたので、それをリリースしてみます。

対象は、 gradle obake plugin です。

If you have an existing plugin with ID foo and are GitHub user “bar”, a suitable new plugin ID would be com.github.bar.foo.

私の場合、bitbucketを公開repositoryとして使っていたので、org.bitbucket.grimrose.obake としました。

自分のドメインを持っている方であれば、org.example.plugin_id みたいになると思います。

gradle をIDに含めなる必要はないので、注意してください。

既に、Gradle Pluginを作っている場合は、既存のpropertiesを META-INF/gradle-plugins/${Gradle_plugin_ID}.properties へ変更してください。

新たに追加しても大丈夫みたいです。

2. Bintray へアップロード

bintray/gradle-bintray-plugin を使うことで、 簡単にアップロード出来るようになります。

bintray pluginについてはサンプルがあるので、bintray/bintray-examples を参考にしてください。

Bintrayのアカウントがない場合、GradleでBintrayにアップロードする手順 を参考にしてください。

3. JCenterへ登録

mavenのrepositoryへリリースしたjarは、JCenterで公開出来るようになります。

詳細は、Including Your Packages in JCenter を参考にしてください。

完了すると、以下の様なMessageが返ってくるので、それまで待ちましょう。

Your request to include your cool package /grimrose/maven/gradle-obake-plugin in Bintray’s JCenter has been approved.

4. Gradle Plugins repositoryへ登録

Gradle Plugins Bintray repo へ移動します。

Include My Package ボタンを押すと、未登録のパッケージが表示されるようになります。

そのまま申請すれば、完了です。

完了すると、以下の様なMessageが返ってくるので、それまで待ちましょう。

Your request to include the package /grimrose/maven/gradle-obake-plugin in the repo /gradle/gradle-plugins has been approved.

5. リリースするversionに’gradle-plugin’の属性を付与

もし、アップロードしたversionに gradle-plugin の属性がついてないと、Gradle Plugins repositoryへ登録されません。

手動で付ける場合は、公開するversionを選んで、中央あたりにある Edit を押します。

次に、Attributes List を選択し、Add New Attribute を押します。

表示された Name には、gradle-plugin を、Value には以下のような値を入力します。

«id»:«group»:«name»

今回の場合、org.bitbucket.grimrose.obake:org.bitbucket.grimrose:gradle-obake-plugin となります。

右の + ボタンを押すと入力した属性が追加されます。

最後に、Update ボタンを押すと完了です。

About This Version の項目に gradle-plugin の項目が追加されていれば、成功です。

bintray pluginであれば、bintray.pkg.version.attributes ブロックに定義しておくことで、アップロードの際に自動的に属性をつけてくれます。

6. リリース完了

全て成功したら、早速 Gradle plugin portal で検索してみましょう。

リリース直後であれば、一番上に自分のpluginが表示されていると思います。

おめでとうございます、これで完了です。

公開したGradle pluginの使い方

公開したGradle Pluginを利用する場合、build.gradle に以下のコードを追加します。

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath "org.bitbucket.grimrose:gradle-obake-plugin:0.6"
  }
}

apply plugin: "org.bitbucket.grimrose.obake"

2.1以降は、以下の様な書き方が出来る模様です。

plugins {
  id "org.bitbucket.grimrose.obake" version "0.6"
}

最後に

一度、承認されれば、以降リリースの度に自動的に反映されます。

元々Bintrayで成果物を管理していたお陰で、早く適用することが出来ました。

他の言語のビルドツールのようなPluginがどんどん増えると思うので、とても楽しみです。

Gradleも2.1で期待してる機能が追加されるみたいなので、期待して待ってます。

Grainの紹介

わいわいGroovy ~ 教えてG*小ネタ大会 - JGGUG G*ワークショップZ Jun 2014Grain を紹介してきました。

併せて今回のスライドは、Grainを利用して作ってみました。

grimrose/jggug-jun-2014

公開先はこちら

http://grimrose.github.io/jggug-jun-2014

静的サイトを作るプロダクトは、JekyllOctopress などがありますが、Groovyで作られたのがGrainです。

今回は、Grain Theme Template を利用しましたが、Octopress Theme もあるので、Blogを書くことも出来ます。

また、GitHub Pagesで公開する場合には、コマンド2つだけで出来るので、簡単です。

時間が足りなくて、デモで出来なかったのは残念でした。

公開のタスクは、Grain Gradle Plugin の場合、以下のコマンドを実行するだけで出来ます。

まず、previewで確認して、完成したらHTMLを生成します。

$ gradle grainGenerate

そして、デプロイします。

$ gradle grainDeploy

プロジェクトのGitHub Pagesの場合 gh-pages branchを作る必要がありますが、これはGrainが自動的に作成してくれます。

その他にもいろいろと興味深い機能があるので、今後も使っていこうと思います。

ScalaをVert.xで利用する

渋谷Java

第五.五回 #渋谷java

http://connpass.com/event/5482/

Vert.x de Scala

grimrose / shibuya-java-05-5

今回の発表に向けて、何か新しい事をしてみたいと思って色々と考えてました。 スライドをhtmlで作るのをやってみたいと思っていたので、今回はそれをテーマにしてみました。 挑戦する内容は、以下の項目を上げてみました。

  • Scala
  • Jade
  • reveal.js

その他、採用したものについて色々と補足してみたいと思います。

祝! lang-scala-1.0.0

vert-x / mod-lang-scala

ここ数日で一気にアップデートされました。次の2.1.0から標準で入るっぽいです。

[lang-scala] mod-lang-scala 1.0.0 is out!

Scalaで Netty ベースのフレームワークというと Finagle が有名ですが、Vert.xもScala Readyとなったことで非同期処理のノウハウが共有されていくといいと思います。

reveal.js

hakimel / reveal.js

htmlをスライドにするプロダクトは様々ありますが、組み合わせて使うならこれが最適だと思います。

特にPDFに出力出来る機能を備えているのは、ありがたいと思います。

ただ、PDFで出力するにはレイアウトを上手く扱う必要があるので、作りながら微調整するといいと思います (作った後からPDFで出力してみたら、残念な結果になってしまったので)。

Scalate

Scalate

reveal.jsに渡すhtmlを生成するのに、Scalaではどの形式なら可能か調べていたところ、テンプレートエンジンとしてScalateが見つかりました。

Scalateは、今回採用したJade以外にMustache、Scaml、SSP、Scueryが利用できます。

Jadeの中でScalaの構文が使えたり、色々と出来るのが面白いと思います。

vertx-gradle-plugin

darylteo / vertx-gradle-plugin

Vert.xプロジェクトを作る際は、vert-x / vertx-gradle-template を使うのが公式で推奨されています。

今回は、非公式ではありますが、Gradleのpluginがあったので試して見ました。

ただ、scalaだけ使いたいのにgroovyのサポートが無いとまともに動かない、modzipにしたものの依存関係のjarが足りない等、まだ未成熟な箇所が見受けられました。

しかし、build.gradleだけでほぼ動作可能な環境を作れるのは、やはりありがたいので今後のアップデートと公式の採用を期待したいと思います。

成果

最終的に出来たスライドはこちら↓

http://grimrose.github.io/shibuya-java-05-5

おわりに

Vert.xの概要等は、@muraken720 さんのスライドを見ていただくのが一番だと思っていたので、紹介させて頂きました。

あと、Vert.x がいいね!(第1回:入門する) がまとまっていて読みやすいので、 Vert.xって何だろと興味を持たれた方は、是非読んでください。

Java 8がリリースされ、個人的にVert.xで期待しているのはNashornなのです。

NashornによってRhino以上のパフォーマンスを得られることが出来れば、あのNode.jsに匹敵するプラットフォームになるのではと考えてます。

もう一つは、Node.JS for the JVMと銘打つ Nodyn です。

この2つが今年のVert.xで一番期待できるコンテンツだと思うので、注目して行きたいと思います。