いますぐ採用すべきJavaフレームワークDropWizard(その２)


Dropwizardについての続きです。
[前回](http://qiita.com/ko2ic/items/cfe5b2f4593b705f9463)は以下の説明をしました。

* mavenでのbuild
* Configurationクラス
* Applicationクラス
* Resourceクラス
* Representationクラス
* HealthCheck機能

今回は前回のサンプルに以下を追加していきます。

* 静的ファイルの表示
* テンプレートエンジンによる動的ファイルの表示
* ssl通信
* 認証

# 静的ファイルと動的ファイル

## maven設定

静的ファイルはdropwizard-assets
動的ファイルはdropwizard-views-freemarker、またはdropwizard-views-mustache
に依存させます。

```pom.xml
    <dependency>
      <groupId>io.dropwizard</groupId>
      <artifactId>dropwizard-assets</artifactId>
      <version>${dropwizard.version}</version>
    </dependency>    
    <dependency>
      <groupId>io.dropwizard</groupId>
      <artifactId>dropwizard-views-freemarker</artifactId>
      <version>${dropwizard.version}</version>
    </dependency>
    <dependency>
      <groupId>io.dropwizard</groupId>
      <artifactId>dropwizard-views-mustache</artifactId>
      <version>${dropwizard.version}</version>
    </dependency> 
```

## Resourceクラス

ポイントは```@Produces```でリソースから返されるMIMEタイプを指定することくらいです。


```ViewResource.java
@Path("/views")
public class ViewResource {
	@GET
	@Produces("text/html;charset=UTF-8")
	@Path("/freemarker")
	public View freemarkerUTF8() {
		return new View("/views/ftl/utf8.ftl", Charsets.UTF_8) {
		};
	}

	@GET
	@Produces("text/html;charset=UTF-8")
	@Path("/mustache")
	public View mustacheUTF8() {
		return new View("/views/mustache/utf8.mustache", Charsets.UTF_8) {
		};
	}
}
```

上記で利用しているViewクラスはDropwizardでViewを表現するためのabstractクラスになります。
HTMLを表示したい場合は、このViewクラスでpublicなオブジェクトを返すGetterメソッドを作ります。
例えば、以下のようにPersonクラスを返して、templateで表示します。

```
public class PersonView extends View {
・・・
	public Person getPerson() {
		return person;
	}
}
```
```
<html>
    <body>
        <h1>Hello {{person.fullName}}</h1>
    </body>
</html>
```

Viewクラス自身のpublicメソッドは@JsonIgnoreが指定されているので、jsonでは表示されないようになっています。

```io.dropwizard.views.View.java
    @JsonIgnore
    public String getTemplateName() {
        return templateName;
    }
    @JsonIgnore
    public Optional<Charset> getCharset() {
        return Optional.fromNullable(charset);
    }
```

## テンプレート

```src/main/resources/views/utf8.ftl
<html>
<body>
<h1>This is an example of a freemarker</h1>
文字コード：${charset}
</body>
</html>
```

```src/main/resources/views/utf8.mustache
<html>
<body>
<h1>This is an example of a mustache</h1>
文字コード：{{charset}}
</body>
</html>
```

## Applicationクラス

BundleクラスとResourceクラスを登録します。
AssetsBundleクラスとViewBundleクラスはDropwizardで用意されているクラスになります。
BasicAuthProviderは、Basic認証用の組み込みクラスになります。

```HelloWorldApplication.java
	@Override
	public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
		bootstrap.addBundle(new AssetsBundle());
		bootstrap.addBundle(new ViewBundle());
	}
	@Override
	public void run(HelloWorldConfiguration configuration,
			Environment environment) throws ClassNotFoundException {
            ・・・
            environment.jersey().register(new ViewResource());
            ・・・
    }
```

## 静的ファイル

静的ファイルは```assets```ディレクトリに置きます。
これはAssetsBundleクラスのデフォルトです。コンストラクタで変更できます。

```src/main/resources/assets/js/example.js
alert('sample');
```

## 動作確認

```mvn package```でjarを作成後、起動すると新しく登録したResourceのURIが表示されています。

```
$ java -jar target/spike-dropwizard-1.0-SNAPSHOT.jar server example.yml
INFO  [2014-06-08 13:30:34,302] io.dropwizard.jersey.DropwizardResourceConfig: The following paths were found for the configured resources:
・・・
    GET     /views/freemarker (com.github.ko2ic.resources.ViewResource)
    GET     /views/mustache (com.github.ko2ic.resources.ViewResource)
```

対応するURIを呼び出すと変換されたHTMLが表示されます。

```
$ curl http://localhost:8080/views/freemarker
<html>
<body>
<h1>This is an example of a freemarker</h1>
文字コード：Optional.of(UTF-8)
</body>
</html>

$ curl http://localhost:8080/views/mustache
<html>
<body>
<h1>This is an example of a mustache</h1>
文字コード：Optional.of(UTF-8)
</body>
</html>
```

静的ファイルは```/assets/ファイルパス```で呼び出します。

```
$ curl http://localhost:8080/assets/js/example.js
alert('sample');
```

# SSLと認証

## SSL

SSLは、keystoreを作成して設定をするだけでアクセスできました。
https://localhost:8443/hello-world

```example.yml
server:
・・・
    - type: https
      port: 8443
      keyStorePath: example.keystore
      keyStorePassword: example
      validateCerts: false
```

以上です。次は認証です。

## maven設定

dropwizard-authの依存を追加します。

```pom.xml
    <dependency>
      <groupId>io.dropwizard</groupId>
      <artifactId>dropwizard-auth</artifactId>
      <version>${dropwizard.version}</version>
    </dependency>   
```

## Representationクラス

ただのドメインクラスです。

```
public class User {
    private final String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
```

## Authenticator

認証用のインターフェイス```Authenticator```を実装します。
認証OKの場合に```Optional.of(p)```、NGの場合は```Optional.absent()```を返します。
ここで引数になっている```BasicCredentials```はDropwizardのBasic認証用のクラスになります。
このサンプルの場合は、user/passでbasic認証が通ります。

```ExampleAuthenticator.java
public class ExampleAuthenticator implements
		Authenticator<BasicCredentials, User> {
	@Override
	public Optional<User> authenticate(BasicCredentials credentials)
			throws AuthenticationException {
		if ("user".equals(credentials.getUsername())
				&& "pass".equals(credentials.getPassword())) {
			return Optional.of(new User("ko2ic " + credentials.getUsername()));
		}
		return Optional.absent();
	}
}
```

## Resourceクラス

メソッドの引数に```@Auth```を付けることで認証対象のメソッドになり、Authenticator#authenticate()の戻り値が渡されます。

```ProtectedResource.java
@Path("/protected")
@Produces(MediaType.TEXT_PLAIN)
public class ProtectedResource {
	@GET
	public String showSecret(@Auth User user) {
		return String.format("Hey there, %s. You know the secret!",
				user.getName());
	}
}
```

## Applicationクラス

```HelloWorldApplication.java
	@Override
	public void run(HelloWorldConfiguration configuration,
			Environment environment) throws ClassNotFoundException {
            ・・・
			environment.jersey().register(
				new BasicAuthProvider<>(new ExampleAuthenticator(),
						"SUPER SECRET STUFF"));
		    environment.jersey().register(new ProtectedResource());
            ・・・
    }
```

## 動作確認

```
$ curl -u user:pass http://localhost:8080/protected
Hey there, ko2ic user. You know the secret!
```