Plastc

複数のカードを一つにまとめられる Coin とかとおなじようなアレ。
Coin と違うのは、IC チップや NFC にも対応している点。

公式ページは https://plastc.com/ です。

以下、メモ。

  • EMV 規格に対応した IC チップ
  • NFC 対応はあるけど、Type F (Felica) はさすがにしていないだろうなぁ
  • 手持ちカードの登録は、Plastc のセットの中にカードリーダがあるらしいので、それで読ませるだけだそうな
  • 磁気テープ対応はしているので T ポイントカードとか Ponta とかは1つにできるかも
    • 見た目が違うので店員が混乱/ダメっていう可能性はある
  • 専用スマホアプリは iOSAndroid
  • 事前申し込みで $155 になるのと、保証期間が 2 年になる。Free lifetime subscription がついている(ずっとということかな?)
  • 通常申し込みは $180 で、18 ヶ月分のサブスクリプションがついている. サブスクリプションは $50/year だそうな

Spring Boot で 例外ハンドリング

Spring Boot での例外ハンドリングの方法について調べたので、そのメモです。
*1

実際に試していないので、問題なく動作するのかはわからないですが、 http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc の内容でほぼ足りそうです。

例外に直接 HTTP Status を紐付けてしまう (Using HTTP Status Codes)

例外クラスに @ResponseStatus をつけることで、Spring MVC の方で処理してくれるっぽいです。

@ResponseStatus(value = NOT_FOUND, reason = "Resource is not found.")
public class ResourceNotFoundException extends RuntimeException {
    ...
}

しかし、これだとエラーレスポンスのボディに JSON で詳細情報を返すのはできなさそう……

Controller クラスごとに例外ハンドリング (Controller Based Exception Handling)

いままで Spring MVC で普通にやっていたのと同じように、Controller クラス内に @ExceptionHandler のついた例外ハンドリングのメソッドを用意するだけです。

@Controller
public class FooController {
    // こんな感じ
    @ExceptionHandler
    @ResponseStatus(NOT_FOUND)
    public void notFound(ResourceNotFoundException ex) {
        // N/A
    }
}

@ResponseBody もつければ、JSON 形式で詳細情報を返すことはできるはず。
しかし、この方法はシステム全体で共通のエラーハンドリングには向かない。
抽象親クラスつくるのはおすすめしない。というか、いまどき共通の機能を抽象親クラスにまとめるとか、ありえんでしょう……
(mix-in ならアリかも?java8ならインタフェースのデフォルト実装の機能を使うことで mix-in のようなことができるので、もしかしたらそれで出来るかも?)

システム全体での例外ハンドリング (Global Exception Handling)

@ControllerAdvice *2をつけたクラスを用意することで、すべての @Controller クラスに対する共通の設定を記述できる。
いってみたら、AspectJ で実装を Weaving するのに似ている。

@ControllerAdvice のクラスでは @ExceptionHandler, @InitBinder, @ModelAttribute アノテーションをつけた三種類のメソッドを定義できるらしい。
@ExceptionHandler だけでなく、@InitBinder も使えるのは嬉しい。空文字だったら null にしてしまうとか、そういうことが一箇所で済む。

@ControllerAdvice
public class FooAdvice {
    @ExceptionHandler
    @RespnseStatus(NOT_FOUND) 
    public void notFound(ResourceNotFoundException ex) {
        // N/A
    }
}

これで、Controller の抽象親クラスを作るというアンチパターンから脱出できる……(といいな)

*1:たぶん、Spring Boot 関係ない。Spring MVC での話ですね……

*2:Spring 3.2 からサポートしていたらしい。 http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html

mixi-inc/AndroidTraining で Android アプリ開発の学習中

スマートフォンのアプリ*1を作れるようになっておきたいと思い、GitHub にある mixi-inc/AndroidTraining で学習することにしました。

開発環境

AndroidStudio

AndroidTraining では Eclipse に ADT を入れていますが、私は IntelliJ がベースとなっている Android Studio を利用しています。IntelliJ カッコ良いんで。
Android Studiohttp://developer.android.com/sdk/installing/studio.html あたりからダウンロードしました。
ダウンロードしたバージョンは 0.3.2 だったのですが、起動時に最新版があるよ!と通知されるので即更新して 0.4.2 になっています。

Android Studio を起動したら、まず最初に SDK をダウンロードしました。ツールバーにある SDK Manager のアイコンをクリックして、SDK Manager から必要そうなものにチェックを入れて Install Package しています。おそらく初回では、最初からいくつかのパッケージが選択・削除されている状態だと思うので、そのまま Install Package ボタンをクリックしたような記憶があります。

Genymotion

Android の高速エミュレータです。http://www.genymotion.com/ から入手できます。要アカウント登録。
Genymotion は VirtualBox 上で動作するので、VirtualBox も必要です。
http://dev.classmethod.jp/smartphone/android/genymotion-install/ あたりを参考にインストールしました。

SDK にも標準でエミュレータがついているのですが、Intel x86 Emulator Accelerator (HAXM) を有効にしてもちょっと遅い感じがあります。Genymotion は起動も描画も十分に早く、またエミュレータ自体のウィンドサイズに合わせて拡大/縮小される、GPSやカメラなどの偽装も簡単にできるのが良いです。

Genymotion Plugin

AndroidStudio でビルドしたアプリケーションのデプロイ先として Genymotion を選択できるようにするために必要(と思う)なので入れておきます。
AndroidStudion の Preferences -> Plugin で Browse Repositories ボタンをクリックするとプラグインの一覧が表示されます。その中から Genymotion プラグインを選択して Download and Install します。

Tips

AndroidStudio を使っていて、なんだかわからないけどおかしいなと思った時にしている事のメモです。

レイアウトファイルに記述している FQCN が赤くなっている*2

メニューから File -> Invalidate Caches / Restart... をクリックし、表示されたダイアログの Invalidate and Restart をクリックしてキャッシュのクリアおよび再起動で解消しました。

依存ライブラリを追加したい

依存ライブラリを利用するモジュールの build.gradle に dependencies ブロックを追加します。
例えば twitter4j-stream を追加するならば以下のようになります。

dependencies {
    compile group: 'org.twitter4j', name: 'twitter4j-stream', version: '3.0.5'
}

Gradle についてはユーザガイドを日本語訳されたありがたい方いるので、それを参考にすると良いかと思います。
ユーザガイドの日本語訳版は http://gradle.monochromeroad.com/docs/userguide/userguide.html になります。

依存ライブラリの追加が反映されない?

メニューから Tools -> Android -> Sync Project with Gradle Files をクリックします。ツールバーにもあるのでそちらでもOKです。
コード補完したときに候補に出てくるようになります。

依存ライブラリ追加したら、ビルドに失敗するようになった

ビルドに失敗し、"META-INF/LICENSE.txt" が重複しているよ!みたいなメッセージが出ている状況のことです。
build.gradle の android の packagingOptions ブロックに exclude に上記のファイル名を指定します。

android {
  ...
  packagingOptions {
    exclude 'META-INF/LICENSE.txt'
  }
}

*1:私の周りでは、よく「クライアントアプリ」と呼称されている気がするが、Windows 上などで動作するアプリと区別がつかなくて違和感を感じる

*2:AndroidStudio側でクラスをうまく認識できていないみたいですね。ビルドはGradleがやるのでできました。

Dispatch を使ってみる

このエントリは Scala Advent Calendar の 18 日目になります。
Dispatch というライブラリを使ってみます。

Dispatch とは

Dispatch というのは、Scala 用 の HTTP クライアントライブラリです。Dispatch には classic と reboot という二種類があり、前者は古い方、後者は一から書き直された新しい方っぽいです。
そして、「Dispatch scala」でみつかる http://dispatch.databinder.net/Dispatch.html は reboot の方です。でも、github で 単に dispatch となっているのは classic で、reboot の方は dispatch/reboot です。ドキュメント上は無印=reboot、github上は無印=classicという感じでなんだか混乱します。

今回使用するのは新しい方の Dispatch (つまり reboot の方) です。以降は reboot の方についての記述になります。

Dispatch では実際の HTTP 周りの処理を async-http-client に任せていて、Dispatch 自体はこのライブラリに対する薄いラッパーのような感じになっています。そのため実際に使用する場合、async-http-client の方を調べる必要があるかもしれません。

準備

Dispatch を利用できるように、以下を記述した build.sbt ファイル*1を作成します。
依存ライブラリに dispatch-core を指定しているだけです。また、JSON を扱えるように dispatch-json4s-native も追加しておきます。

libraryDependencies ++= Seq(
  "net.databinder.dispatch" %% "dispatch-core" % "0.11.0",
  "net.databinder.dispatch" %% "dispatch-json4s-native" % "0.11.0"
)

sbt の console 上で試す

sbt の console を起動して実際に Dispatch を使用して GET や POST をしてみたいと思います。
依存ライブラリをダウンロードするため、初回の起動はちょっと時間がかかるかもしれません。


$ sbt console
[info] Set current project to root-2013-advent-calendar (in build file:/C:/development/workspaces/sandbox/scala/2013-advent-calendar/)
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.2 (Java HotSpot(TM) Client VM, Java 1.6.0_23).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import dispatch._, Defaults._
import dispatch._
import Defaults._

scala>

dispatch パッケージ直下に主要な部品が定義されているので、 import dispatch._ で利用できるようにします。
また、 dispatch.Defaults には Future の実行で必要な暗黙のパラメータに渡す値が定義されているようです(defaults.scala)。

GET

GET リクエストを発行してみます。


scala> Http(url("[]https://api.github.com/gists?per_page=1[]") OK as.String)
res1: dispatch.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@1e9ed79

scala> res1()
res2: String = [{"url":"[]https://api.github.com/gists/7995189[]","forks_url":"http
s://api.github.com/gists/7995189/forks","commits_url":"[]https://api.github.com/g[]
~~(snip)~~
2-16T21:59:24Z","description":"","comments":0,"user":{"login":"thion","id":3336
77,"avatar_url":"[]https://gravatar.com/avatar/3d082acb2ebd10448ee5cf790cdc3c96?d[]
=https...

scala>

url("...") の部分でリクエストを構築しています。上記の例では URL を文字列で指定していますが、ホスト名、パス、クエリパラメータを別個に指定することも可能です。request.scala にリクエストの構築に使用する部品が定義されています。

リクエストの結果となるレスポンスをどのように扱うかを OK as.String の部分で指定しています。レスポンスが成功(2xx)の場合のみ処理して、レスポンスボディを文字列として取り出すレスポンスハンドラを指定しています。OKhandlers.scala に、as.Stringas/core.scala に定義があります。
Http(...) で構築したリクエストを実行し、その結果をレスポンスハンドラで処理しています。実際には Http(...) の戻り値は Future インスタンスのため、すぐにレスポンスが得られているわけではありません。res1()*2することで、レスポンスが取得されるまでブロックして、その値を取り出しています。*3


以下は、リクエスト構築の際に host 等を使用する場合の例になります。また、as.json4s.Json を指定することでレスポンスを文字列としてではなく JSON として取り出しています。*4


scala> Http(host("api.github.com").secure / "gists" <<? Map("per_page" -> "1") OK as.json4s.Json)
res3: dispatch.Future[org.json4s.JValue] = scala.concurrent.impl.Promise$DefaultPromise@abedf1

scala> import org.json4s._
scala> import org.json4s.native.JsonMethods._
scala> pretty(render(res3()))
res4: String =
[{
"url":"[]https://api.github.com/gists/8004290[]",
"forks_url":"[]https://api.github.com/gists/8004290/forks[]",
~~(snip)~~
"comments":0,
"user":{
...
scala>

POST

続いて POST リクエストを発行してみます。
基本的には GET の場合と同様にリクエストを構築して実行するだけです。


scala> import org.json4s.native.Serialization, Serialization.{write}
import org.json4s.native.Serialization
import Serialization.write

scala> write(Map("public" -> true, "files" -> Map("file1.txt" -> Map("content" -> "String file contents"))))
res5: String = {"public":true,"files":{"file1.txt":{"content":"String file contents"}}}

scala> Http(host("api.github.com").secure / "gists" << res5 OK as.json4s.Json)
res6: dispatch.Future[org.json4s.JValue] = scala.concurrent.impl.Promise$DefaultPromise@2407b8

scala> pretty(render(res6()))
res7: String =
{
"url":"[]https://api.github.com/gists/8005261[]",
"forks_url":"[]https://api.github.com/gists/8005261/forks[]",
~~(snip)~~
"description":null,
"comments":0,
...
scala>

<< を使用してリクエストボディに JSON 文字列を指定しているのが、GET の例との差になります。*5
リクエストに対してどのような操作が可能かは requests.scala に定義されている RequestVerbs を継承している各種 trait を見るとわかるかと思います。

また、GET / POST 両方の例とも、GET なのか POST なのかを明示的に指定していません。これはリクエストのデフォルトが GET になっていて、またリクエストボディを指定した場合はデフォルトが POST となるため、上記の例では明示的な指定が不要でした。host("...").GET のように記述することで明示できます。


以上、簡単にではありますが Dispatch を試すときの手がかりになれば幸いです。

おまけ

Verbs 引数 説明
HEAD, GET, POST, PUT, DELETE, PATCH, TRACE, OPTIONS - HTTP メソッドを指定
url - リクエストの URL 文字列を取得
/ String *6 パスを追加
secure - https:// でアクセスする
<:< Traversable[(String, String)] ヘッダを指定
<< Traversable[(String, String)] リクエストボディにパラメータを指定
<< String リクエストボディに文字列を指定
<<< java.io.File ファイルアップロード
<<? Traversable[(String, String)] クエリパラメータを指定

*1:sbtを使用します

*2:EnrichedFutureで Future に apply メソッドが追加されています

*3:Future の使い方については割愛させていただきます

*4:json4s については割愛

*5:GET の例では <<? を使用してクエリパラメータを指定していました

*6:toString されるオーバーロードがあるので AnyVal でもOK

NAS4Free 9.1 で HDD へのインストールに失敗する場合

LivceCD からの起動で HDD へのインストールに失敗する場合の対処。
ML115G5 に最新版のNAS4Freeをインストールしようとしたら、パーティションの作成とかで失敗した。
以下によりインストールできた。


1. ブート途中でSafeモードとかを選択出来る画面が出ると思うので、ブートを一時停止して Prompt ? を表示するモードをえらびます。 9.1.0.1(revision 847) ですと選択肢の5.になってました。

2. 表示されたプロンプト(OK とか出ていた気がする)で以下のように入力して、ブートを続行。

set kern.geom.raid.enable=0
boot

3. HDD にアクセスできた!

LiveCD の設定値がいまいち?なのかな。USB メモリにインストールして起動であれば、HDD も問題なく読めるし。

fstab で CIFS のファイルシステムを記述しているけど、マウントされない場合

netfs サービスが起動していない可能性が高い。

"/sbin/chkconfig --list netfs" と打って、on となっているか確認してみる。
off になっている場合は "/sbin/chkconfig netfs on" と打って on にしておく。

これでもダメな場合は _netdev オプションを追記してみる。

Windows で nslookup で IP アドレスは引けるけど、ping は通らない場合の対処

DNSClient サービスが DNS 情報をキャッシュしているために発生していることが多い。
ipconfig /flushdns では効果が無い場合は、DNSClient サービスを再起動するとなおる。

というか、別にキャシュしなくてもいいや・・・ということで、DNSClient サービスを止めてみた。
今のところ、問題なく動いているっぽい。