Quantcast
Channel: 行きあたりばったりエンジニアの日記
Viewing all 88 articles
Browse latest View live

Spring Boot 1.4でThymeleaf 3を使う

$
0
0

プロジェクト作成は、Spring Initializrとかで作成済みの前提です。

Spring Boot 1.4では、デフォルトでThymeleaf 2が使われます。

Thymeleaf 2ではXHTMLで書く必要がありますが、Thymeleaf 3だと完全にピュアなHTMLで書くことが可能です。

pom.xmlのpropertiesに下記の記述を追加します。

<properties><!-- その他のプロパティは省略 --><thymeleaf.version>3.0.1.RELEASE</thymeleaf.version><thymeleaf-layout-dialect.version>2.0.1</thymeleaf-layout-dialect.version></properties>

Thymeleaf 3のバージョンと共に、Thymeleaf Layout Dialectのバージョンも指定する必要があります。

これだけで完了で、あとはビルドしなおせばThymeleaf 3が使われます。

Bean定義なども記述する必要はなく、本当にこれだけでおしまいです。

Gradleの場合はこちらを参照してください。

Support Thymeleaf 3 · Issue #4393 · spring-projects/spring-boot · GitHub


【回避方法あり】Payara 4.1.1.164には認証に関するバグがありました

$
0
0

環境

Payara Web ML 4.1.1.164 確認していませんが、Full Profileでも同じバグがある可能性があります。 また、4.1.1.163以前のバージョンには、このバグはありません。

現象

JDBCリソースやレルムの設定を正しく行っても、アプリケーションでフォーム認証ができません。 具体的には、ログイン画面から正しいID・パスワードを入力してログインしても、403エラーになります。

原因

「デフォルトロールマッピングプリンシパル」の有効化が認識されないようです。 これは、管理コンソール・asadminコマンド・domain.xml直接書き換え、いずれを行なってもダメでした。

いつ修正されるのか

来年第1四半期にリリース予定のPayara 4.1.1.171で修正される予定です。

回避策

アプリケーションのWEB-INFフォルダにglassfish-web.xmlというファイルを作成し、下記のように記述してください。 こうすると、うまく「デフォルトロールマッピングプリンシパル」の有効化が認識されるようになります。

<glassfish-web-app><property name="default-role-mapping"value="true"><description>Enable default group to role mapping</description></property></glassfish-web-app>

もっと詳しいことは

GitHubにIssueを書きましたので、ご覧ください。

403 error occurs when Form-Authentication succeeded PAYARA-1244 · Issue #1213 · payara/Payara · GitHub

サンプルコードはこちら。

GitHub - MasatoshiTada/form-authentication-sample

「新人研修や本では教えてくれないJava!」というタイトルで発表してきました #jjug_ccc

$
0
0

昨日のJJUG CCC 2016 Fallで発表してきました。ありがたいことに、CCC登壇は6回連続6回目になります。

speakerdeck.com

朝イチ10時から、かつ基調講演の裏番組にもかかわらず、120名くらいの部屋がほぼ満席となりました。

ご参加いただいた皆様、そして運営されていたJJUG幹事やボランティアスタッフの皆様、本当にありがとうございました。

また、感想ブログや全セッションのスライドは、こちらにまとまっています。

GitHub - jjug-ccc/slides-articles-2016fall: JJUG CCC 2016 Fallの発表資料およびブログ記事まとめ

発表内容

この発表をしようと思った理由

僕は研修トレーナーが仕事なので、毎年春には新人研修を担当しています。それ以外の期間は、新人以外の一般のお客様向けに、自社開催の研修だったり、お客様先で研修したりしています。

今回の発表のような内容は、通常、新人研修では扱いません。また、1つにまとまった書籍や資料が無いためか、新人でなくても意外とご存知ない方が多いと感じていました。

だったら資料を作って公開しちゃえ!と思ったのがきっかけです。

発表の最初に、「どちらかというと『初心者』だという方?」「どちらかというと『指導役』だという方?」と全体に対して伺ったところ、ちょうど半々くらいでした。

資料を公開したツイートは、かなり多くのリツイートやいいねをいただきました。

また、反応もいくつかいただけました。お役に立てたようで、とても嬉しいです!

ちなみに、Speaker Deckにアップしているスライドは、本来話したかった内容が全て含まれた「完全版」です。

ただ、想像以上にボリュームが膨らんでしまったため、発表はその抜粋版で行いました。発表を聞いていただいた方も、ぜひこの「完全版」をご確認ください。

この資料はPDFでアップしていますので、ダウンロードや社内でのご利用等は、ご自由にどうぞ!

著作権は所属会社であるカサレアルに属しますので、有償のサービスで使うことだけはご遠慮ください)

聴講したセッション

Java EE - What's Next? #ccc_a2

Oracleの方によるJava EE 8、Java EE 9の今後のプランに関するセッションでした。以前、JavaOne報告会で寺田さんがお話されていたので、それを再確認する感じでした。

冒頭、「Microservices」や「Cloud Native」という言葉が出てきたので、Oracleもこういうところに本腰を入れていくんだなあ、と改めて実感しました。

僕の理解では、本丸は2018年末に出るJava EE 9で、EE 8はその前フリ、という感じです。

MVC 1.0が(おそらく)標準では入らなくなることは残念ですが、Java EEが前進したので、個人的には全体的に満足しています。

余談ですが、Anilさんの英語は聞き取りやすく、ちょっとばかし自分の英語ぢからアップを感じ取れました。

でも、50分間は集中力が持たず、後半は通訳の方に頼りっぱなしでした。まだまだやなあ・・・。

Event Driven Microservices with Spring Cloud Stream #ccc_ab3

最近はSpring業務も多いので、槙さんのセッションは外せませんでした。

メッセージングとかキューは、最近ちょっと使っててとても面白いなあと思ったので、自分でもやってみたいです。

しかし本当に、Springは進んでいるなあ。Java EEも頑張ってほしいなあ・・・。

Spring CloudでDDD的なマイクロサービスを作ってみる #ccc_ab4

2016 SpringでThymeleafのセッションをされた椎葉さんのセッション。

僕はDDD本も読んだことないのでぼんやりとしか知らなかったのですが、ちょっとだけ見えたような気がします。

ソースコードも公開されていたので、後でじっくり確認してみます!

JAX-RS REST Client で Cognitive Service や Excelを操作しよう #ccc_cd5

Microsoft寺田さんのセッション。最近話題のCognitive Serviceを知りたくて参加しました。

音声・画像・動画・テキストから、顔や物体や感情を判定するサービスです。

非常に面白いなあと思いました。色々と活用できる場面がありそうですね。

JPAと DDD の関係で僕が思っていること #ccc_ab6

Qiitaで有名な@opengl_8080さんのセッションです。

公私とも、ずーっとこの方のQiitaにはお世話になっています。去年のCCC Fallで初めてお話ししたのでした。

JPAについて徹底的に調べられていて、それなりにJPA歴がある僕でも「え!?知らんかった・・・」ということが沢山ありました。

やっぱり、しっかり仕様を確認することと、実験することが大事ですね。

Payara Micro の設計と実装 #ccc_ab7

我らがGlassFish User Group Japan会長、蓮沼さんのセッションです。

GlassFishソースコードをフォークして、英国C2B2社がオープンソースで開発しているのが「Payara」です。そして、Payara Microはその組み込みサーバー版です。

このセッションでは、Payara Microのソースコードから、起動・クラスタリング・デプロイの仕組みについて解説されていました。

さすが蓮沼さん、知識が膨大だ・・・。でも、とても興味深かったです。

参加を終えてどう感じたか

マイクロサービスやクラウドネイティブというのが当たり前になりつつある、というのが率直な感想でした。

そして、来年のCCCのがある頃には、完全に「当たり前」のものになっているだろうと思います。

研修、そしてトレーナー自身も、進化を続けていかなければならないと、改めて思いました。

そして、聴くだけで終わらせるのではなく、どれか知った内容を今日から実践してみよう、とも思います。

槙さんが発表されていたSpring Cloud Streamをやってみたいなー!

運営に関して

改めて、JJUG幹事とボランティアスタッフのみなさま、ありがとうございました。そして、お疲れ様でした。

おかげさまで、非常に楽しい1日となりました。

運営が非常にスムーズで、特に問題点のようなものは見つけられませんでした。

敢えて言えば、参加者数が増えたことで、お手洗いが混んでいたなあ・・・というくらいでしょうか。それで次のセッションにちょっと遅刻しちゃったことが何回かありました。

セッション間の10分休憩を15分くらいにすると丁度いいかもしれません。午後に2セッションごとにある40分間の休憩も、体力回復のためとてもありがたいのですが、30分間くらいでも大丈夫と思います。そうすると、トータルでの終了時間(懇親会開始が19時半)は変わらないはずです。

(このことはアンケートにも記入済みです)

あと、聴きたいセッションの時間帯が重なってる!ということが多かったのですが、それはすなわち、どのセッションも魅力的であったということなので、これは致し方ないかと思います。

まとめ

久々に会えた方や、ツイッターでは知っていたものの対面でお話しすることは初めてだった方など、いろんな方にお会いできました。これもCCCの楽しいところですね。

来年も楽しみにしております!

【書評】Spring Microservices(洋書)

$
0
0

www.packtpub.com

Spring Cloudの勉強をするために買いました。

内容としては、

  • Spring Bootの基礎
  • Microservicesとは何ぞや?その背景は?
  • Circuit BreakerやService Discoveryって何ぞや?なぜ必要なのか?
  • Spring Cloudの基礎
  • Docker、Mesos

など、かなり幅広いです(ページ数もそこそこ多い)。

背景やなぜ必要なのか、というところはすごく参考になりました。 また、Spring Cloudでアプリケーションを作るところは、そこそこ多いマイクロサービス(最終的には10個くらいになる)を手順を追いながら作っていくので、手を動かして学びたい人にはうってつけな本です。

総じて良い本だと思いますが、注意点があります。

1つ1つの手順があまり詳しく書いておらず、「え?このソースコード、どのマイクロサービスの!?」と思うことがとても多いです。また、誤植も散見され、そのままだと動かんやろ、という部分もいくつかありました。

正直言って、Spring BootやSpring Cloudが全く初めてという方には向きません。ある程度は学習したことがある方が、より理解を深めるための本だと思います。

Bean Validationでクライアント側のロケールに合わせたメッセージを出力する

$
0
0

やりたいこと

通常のBean Validationでは、クライアント側ではなく、サーバー側のロケールのエラーメッセージになってしまいます。

なので、クライアント側のロケールに合わせて

$ curl -v -H "Accept: text/html" -H "Accept-Language: ja" http://localhost:8080/jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a

としたらValidationMessages_ja.propertiesのエラーメッセージになり、

$ curl -v -H "Accept: text/html" -H "Accept-Language: en" http://localhost:8080/jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a

としたらValidationMessages_en.propertiesのエラーメッセージになり、

$ curl -v -H "Accept: text/html" -H "Accept-Language: cs" http://localhost:8080/jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a

としたらValidationMessages.propertiesのエラーメッセージになるようにします。

独自ResourceBundleLocatorの作成

Bean Validation参照実装のHibernate Validator独自インタフェースです。

ResourceBundleLocatorは、Localが引数で戻り値がResourceBundleなメソッドを持っているので、この中でゴニョゴニョします。

package com.example.rest.validation;

import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;

import java.util.Locale;
import java.util.ResourceBundle;

class NoFallbackControlResourceBundleLocator implements ResourceBundleLocator {
    @Overridepublic ResourceBundle getResourceBundle(Locale locale) {
        ResourceBundle.Control control =
                ResourceBundle.Control.getNoFallbackControl(
                        ResourceBundle.Control.FORMAT_DEFAULT);
        ResourceBundle bundle = ResourceBundle.getBundle("ValidationMessages", locale, control);
        return bundle;
    }
}

ResourceBundleは、指定されたロケールに合致したプロパティファイルが無い場合、デフォルトロケール(僕の環境だとja_JP)のプロパティファイルを選びます。

これは今回のやりたいことに合致しないので、「フォールバック制御」を行っています。

getNoFallbackControl()メソッドによって、ロケールに合致したプロパティファイルが無い場合、ロケール無しのプロパティファイルが選ばれるようになります。

参考資料

櫻庭さんの記事です。上記の内容は、この記事を読んで初めて知りました・・・。

Java技術最前線 - 「Java SE 6完全攻略」第54回 ResourceBundleの新機能 その2:ITpro

独自MessageInterpolatorの作成

MessageInterpolator自体は、Bean Validationで定義されているインタフェースです。

今回は、Hibernate Validatorが持っているMessageInterpolator実装クラスを継承して、メソッドをオーバーライドします。

package com.example.rest.validation;

import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;

import java.util.Locale;

class LocalizedMessageInterpolator extends ResourceBundleMessageInterpolator {

    privatefinal Locale locale;

    LocalizedMessageInterpolator(Locale locale) {
        super(new NoFallbackControlResourceBundleLocator());
        this.locale = locale;
    }

    @Overridepublic String interpolate(String messageTemplate, Context context) {
        returnsuper.interpolate(messageTemplate, context, this.locale);
    }

    @Overridepublic String interpolate(String messageTemplate, Context context, Locale locale) {
        returnsuper.interpolate(messageTemplate, context, locale);
    }
}

コンストラクタでロケールを受け取り、1つ目のinterpolate()メソッド内で利用します。

2つ目のinterpolate()メソッドはどんな時に呼ばれるのかは、まだ不明です... (^^;

参考資料

Hibernate Validatorのドキュメント

Chapter 4. Interpolating constraint error messages

ローカライズしたValidatorの作成

package com.example.rest.validation;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.spi.CDI;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@ApplicationScopedpublicclass LocalizedValidator {

    private ConcurrentMap<Locale, Validator> validatorCache = new ConcurrentHashMap<>();

    public<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
        HttpServletRequest httpServletRequest = CDI.current().select(HttpServletRequest.class).get();
        Locale locale = httpServletRequest.getLocale();
        Validator validator = validatorCache.computeIfAbsent(locale, (keyLocale) ->
            Validation.byDefaultProvider()
                    .configure()
                    .messageInterpolator(new LocalizedMessageInterpolator(keyLocale))
                    .buildValidatorFactory()
                    .getValidator()
        );
        return validator.validate(object, groups);
    }
}

HttpServletRequestからクライアント側のロケールを取得し、LocalizedMessageInterpolatorに渡します。

Validatorの生成を毎回行なうのは効率的でないので、キャッシュしました。

ValidatorFactoryおよびValidatorはスレッドセーフとJavadocに書いてありますので、キャッシュして使い回しても大丈夫なはず・・・です。

僕はあまりスレッドセーフ関連は詳しくないので、ご自分でも十分に調査の上、利用してください。

参考資料

槙さんのスライド

そんなリザルトキャッシュで大丈夫か? #jjug

コントローラークラスの作成

@Path("employee")
@RequestScoped@Produces(MediaType.TEXT_HTML)
publicclass EmployeeController {

    @Injectprivate LocalizedValidator validator;

    @GET@Path("result")
    public ThymeleafViewable result(@BeanParam EmployeeIdForm form) throws Exception {
        // バリデーション実行
        Set<ConstraintViolation<EmployeeIdForm>> violations = validator.validate(form);
        // エラーがあれば入力画面に戻るif (!violations.isEmpty()) {
            HashMap<String, Object> models = new HashMap<>();
            models.put("violations", violations);
            returnnew ThymeleafViewable("employee/index.html", models);
        }

先ほど作成したLocalizedValidatorをDIし、コントローラーメソッド内でバリデーションを実行します。

プロパティファイルの作成

日本語用 src/main/resources/ValidationMessages_ja.properties

employee.id.notblank=社員IDは必須入力です。
employee.id.pattern=社員IDは整数で入力してください。

英語用 src/main/resources/ValidationMessages_en.properties

employee.id.notblank=Employee ID must not be blank.
employee.id.pattern=Employee ID must be integer.

それ以外用(英語のメッセージの先頭に「(Def)」をつけています) src/main/resources/ValidationMessages.properties

employee.id.notblank=(Def)Employee ID must not be blank.
employee.id.pattern=(Def)Employee ID must be integer.

実行

$ curl -v -H "Accept: text/html" -H "Accept-Language: ja" http://localhost:8080/jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: text/html
> Accept-Language: ja
>
< HTTP/1.1 200 OK
< Server: Payara Micro #badassfish
< Set-Cookie: JSESSIONID=43dfaf692f43c4bcdd999837d7c9; Path=/jjug-my-mvc-1.0-SNAPSHOT; HttpOnly
< Content-Type: text/html
< Date: Thu, 09 Jun 2016 08:18:45 GMT
< Content-Length: 644
<
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
(中略)
<ul class="error">
    <li>社員IDは整数で入力してください。</li>

</ul>
(中略)
* Connection #0 to host localhost left intact
$ curl -v -H "Accept: text/html" -H "Accept-Language: en" http://localhost:8080/jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: text/html
> Accept-Language: en
>
< HTTP/1.1 200 OK
< Server: Payara Micro #badassfish
< Set-Cookie: JSESSIONID=43e9b73c50fe3be35f60bd734842; Path=/jjug-my-mvc-1.0-SNAPSHOT; HttpOnly
< Content-Type: text/html
< Date: Thu, 09 Jun 2016 08:19:26 GMT
< Content-Length: 616
<
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
(中略)
<ul class="error">
    <li>Employee ID must be integer.</li>

</ul>
(中略)
* Connection #0 to host localhost left intact
$ curl -v -H "Accept: text/html" -H "Accept-Language: cs" http://localhost:8080/jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /jjug-my-mvc-1.0-SNAPSHOT/api/employee/result?id=a HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: text/html
> Accept-Language: cs
>
< HTTP/1.1 200 OK
< Server: Payara Micro #badassfish
< Set-Cookie: JSESSIONID=43efe0e6f24b7d015771568feb84; Path=/jjug-my-mvc-1.0-SNAPSHOT; HttpOnly
< Content-Type: text/html
< Date: Thu, 09 Jun 2016 08:19:51 GMT
< Content-Length: 640
<
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
(中略)
<ul class="error">
    <li>(Def)Employee ID must be integer.</li>

</ul>
(中略)
* Connection #0 to host localhost left intact

今回のコード

https://github.com/MasatoshiTada/jjug-action-based-mvc/tree/master/jjug-validation

https://github.com/MasatoshiTada/jjug-action-based-mvc/tree/master/jjug-my-mvc

必要最小限のサンプルでThymeleafを完全マスター

$
0
0

この記事は?

Java EE Advent Calendar 2016 - Qiitaの12日目です。

昨日の記事は@yyYankさんの「どうすんのJava EE - Javaプログラマのはしくれダイアリー」でした。明日は@n_agetsuさんです。

Thymeleafは、Javaで作られたテンプレートエンジンです。JSPの代替技術として近年注目されていて、JJUG CCCなどで話を聞いていても、利用事例が増えているように感じます。

ブログ情報も多く、検索すると「チートシート」のようなブログがいっぱい出てきます。

ただ、Thymeleafは多機能なのでチートシートもボリュームがあり、Thymeleafを初めて学習する人にはちょっと重たいなあ・・・と感じていました。

そこで今回は、JSPから移行したい方が、まず最初に理解すべき必要最低限の項目をまとめました。

アジェンダ

  • 環境準備
  • 4つの記法
    • リンク式(@{...}
    • メッセージ式(#{...}
    • 変数式(${...}
    • 選択変数式(*{...}
  • テンプレートの記述
    • 条件分岐(th:ifth:unless
    • 繰り返し(th:each
  • その他
    • ユーテリティオブジェクト(#listsなど)
    • コメント(<!--/* */-->

サンプルコードはGitHubに公開しています。

GitHub - MasatoshiTada/beginning-thymeleaf

環境準備

プロジェクトの作成

MavenまたはGradleを使います。(下記はMavenの例です)

<dependencies>
        ...
        <dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf</artifactId><version>3.0.2.RELEASE</version><scope>compile</scope></dependency>
        ...
    </dependencies>

TemplateResolverTemplateEngineの生成

今回は、サーブレットが1つ、Thymeleafのテンプレートが1つだけのシンプルなプログラムです。

Thymeleafの中心的なクラスが、TemplateResolverTemplateEngineです。

TemplateResolverクラスは、指定された論理的なビュー名(例:"hello")から、物理的なビュー名(例:"/WEB-INF/views/hello.html")を解決する役割を担います。

TemplateEngineクラスは、作成されたテンプレートを元に、実際にレスポンスするHTMLを出力する役割を担います。

まずは、上記2つのインスタンスを生成しておく必要があります。これらのインスタンスは1つずつ生成して、以降の処理では使い回せばOKです。

今回は、サーブレットクラスの初期化処理の中で生成します。

@WebServlet("/hello")
publicclass HelloServlet extends HttpServlet {

    // Thymeleafの出力を書き出すクラスprivate TemplateEngine templateEngine;

    /**     *サーブレットの初期化処理。     * TemplateResolverおよびTemplateEngineを生成する。*/@Overridepublicvoid init(ServletConfig config) throws ServletException {
        super.init(config);

        // TemplateResolverの生成
        ServletContext servletContext = config.getServletContext();
        ServletContextTemplateResolver templateResolver =
                new ServletContextTemplateResolver(servletContext);
        templateResolver.setPrefix("/WEB-INF/views/"); // ビューの保存フォルダ
        templateResolver.setSuffix(".html"); // ビューの拡張子
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // TemplateEngineの生成
        templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
    }
    
    // その他のメソッド省略
}

今回はサーブレットが1つなので、サーブレットの初期化処理で書きましたが、本来のアプリケーション開発であれば、何らかの方法でシングルトンにしておくと良いでしょう。

SpringだったらBean定義すればいいですし*1Java EEならば@ApplicationScopedなプロデューサーメソッドとして作ってもいいでしょう。(詳細は最後の参考資料をご覧ください)

4つの記法

さて、ここから具体的なThymeleafによるテンプレート記述に入ります。

Thymeleafには、大きく分けて4つの記法があります。

リンク式(@{...}

HTMLとかJSPを書いていてけっこう面倒なのが、リンク/CSS/JS/画像などの「パスの記述」ではないでしょうか。

絶対パスで指定するためにコンテキストパスを毎回書いたり、相対パスで書くとプロジェクトのフォルダ構造と、サーバー上で実行される時のパスが違っていて、うまくパスを指定するのが難しかったりします。

こういった問題の対策として、Thymeleafにはリンク式という記法があります。

  • テンプレート
<linkrel="stylesheet"href="../../css/style.css" th:href="@{/css/style.css}">

th:href属性の@{...}の部分がリンク式です。/で始めると、レスポンスされるHTMLには、なんとコンテキストパスが補完されます!

href属性は、サーバーを通さずに直接ブラウザでHTMLを開いたときに利用されます。そして、サーバー上で実行したときには、href属性の値はth:href属性の値で上書きされます。

Thymeleafには、th:xxxという形式の属性がいっぱいあるのですが、基本的にはxxxという属性の値を上書きするものです。

  • レスポンスされるHTML
<linkrel="stylesheet"href="/beginning-thymeleaf/css/style.css">

なぜ、上書きされて消えてしまうhref属性を書くのかというと、直接ブラウザでHTMLを開いてもCSSが適用されるようにするためです。

こうすると、テンプレートをそのままブラウザで開いて、お客様に見せて打ち合わせなどができます。

本番用のソースコードがそのまま画面モックになるのが、Thymeleaf最大の特徴です。

メッセージ式(#{...}

Thymeleafでは、画面上のメッセージをプロパティファイルなどに記述し、国際化ができます。

やり方は簡単で、テンプレートの.htmlファイルと同じフォルダに、「テンプレート名.properties」というファイルを作るだけです。

例えば、hello.htmlに対するプロパティファイルは「hello.properties」「hello_ja.properties」などです。

言語は、クライアントからのAccept-LanguageHTTPリクエストヘッダで指定します。

指定された言語に対応したプロパティファイルがなかった場合は、ロケールなしの「hello.properties」が使われます。

  • hello.properties
backToTop=Back to top
nothingToShow=No users to show.
  • hello_ja.properties
backToTop=トップページに戻る
nothingToShow=表示するユーザーがありません。
  • hello.html(テンプレート)
<p th:text="#{nothingToShow}">表示するユーザーがありません。</p><ahref="../../index.html" th:href="@{/}" th:text="#{backToTop}">トップページに戻る</a>

#{...}の部分がメッセージ式です。「nothingToShow」や「backToTop」は、プロパティファイルのキーを指定しています。

th:text属性は、画面にメッセージを表示するために使われる属性です。

サーバーで実行した時は、th:text属性を指定したタグに挟まれた部分が置き換えられます。

テンプレートに記述している「表示するユーザーがありません。」などのメッセージは、ブラウザで直接開いたときのための仮のメッセージで、サーバーで実行時はプロパティファイルのメッセージで上書きされます。

変数式(${...}

サーブレット側で、テンプレートに値を渡す処理は、こんな感じで書きます。

List<User> userList = ...;

// ビューに渡す値を保存するマップ
HashMap<String, Object> map = new HashMap<>();
map.put("userList", userList);

// レスポンスするHTMLを書き出す
WebContext webContext = new WebContext(request, response,
        getServletContext(), request.getLocale());
webContext.setVariables(map); // 値をビューに渡す
Writer writer = new OutputStreamWriter(
        response.getOutputStream(), StandardCharsets.UTF_8);
templateEngine.process("hello", webContext, writer); // /WEB-INF/views/hello.htmlを書き出す

少し面倒なコードに見えますが、このあたりはフレームワーク化すれば、毎回書く必要は無くなります。

この値をテンプレートで表示するには、変数式を使います。

  • テンプレート
<tr th:each="user : ${userList}"><td th:text="${user.id}">111</td><td th:text="${user.name}">Yumi Wakatsuki</td></tr>

th:eachは繰り返しを記述するもので、後述します)

${...}の部分が変数式です。ほぼJSPのELと同じですね。

ここもth:textを使っているので、タグで挟まれた部分(「111」など)は、サーバー上で実行されたときには置き換えられます。

  • レスポンスされるHTML
<tr><td>1</td><td>User1</td></tr><tr><td>2</td><td>User2</td></tr><tr><td>3</td><td>User3</td></tr>

選択変数式(*{...}

先ほどのユーザーの表示の部分ですが、userというのをIDと名前で2回書いています。

これを簡略化できるのが、選択変数式です。

  • テンプレート
<tr th:each="user : ${userList}" th:object="${user}"><td th:text="*{id}">111</td><td th:text="*{name}">Yumi Wakatsuki</td></tr>

上記の例だと、<tr>開始タグにth:object=${user}と書いています。

こうすると、<tr>で挟んでいる部分では、${user.id}ではなく*{id}と書くことができます。これが選択変数式です。

レスポンスされるHTMLは、変数式の場合とまったく同じになります。

  • レスポンスされるHTML
<tr><td>1</td><td>User1</td></tr><tr><td>2</td><td>User2</td></tr><tr><td>3</td><td>User3</td></tr>

テンプレートの記述

テンプレートでは欠かせない、条件分岐・繰り返しについて説明します。

条件分岐(th:ifth:unless

JSPで言うところの<c:if>に相当します。

<c:choose>に相当するものはありません。つまり、ifに対するelseみたいな記述はできません。

  • テンプレート
<tableborder="1" th:unless="${#lists.isEmpty(userList)}">
    ...
</table><p th:if="${#lists.isEmpty(userList)}">表示するユーザーがありません。</p>

#listsの部分はユーティリティオブジェクトというもの(後述)なのですが、ざっくり言うと、userListが空でなかったら<table>要素の部分のみが、空だったら<p>要素の部分のみが出力されます。

th:unlessは変数式で指定した条件がfalseの時に出力され、th:ifは変数式で指定した条件がtrueの時に出力されます。

  • レスポンスされるHTML(userListが空でない場合)
<tableborder="1">
    ...
</table>
  • レスポンスされるHTML(userListが空の場合)
<p>表示するユーザーがありません。</p>

条件を指定するには、普通のJavaのように==!=などを使うことができます。

不等号については、<>ではなく、lt<相当)、gt>相当)、le<=相当)、ge>=相当)、を使います。

andorで、複数の条件を指定することも可能です。

実は、true/falseだけでなく、下記のものはfalseと判断されます。逆に言うと、falseと下記以外は全てtrueと判断されます。

  • null
  • 0
  • "0"
  • “false”
  • “off”
  • “no”

これは、検索結果などを表示する時に非常に便利です。null比較をしなくて済みますね!

  • テンプレートの例(このコードはGitHubにはありません)
<!--/* th:if="${user != null}" と同じ */--><tableborder="1" th:if="${user}"><tr><td th:text="*{id}">111</td><td th:text="*{name}">Yumi Wakatsuki</td></tr></table>

繰り返し(th:each

前にも少し出てきましたが、繰り返しはth:eachで表します。

下記の場合だと、th:each属性を記述している<tr>要素自体が繰り返し出力されます。

構文はth:each="コレクションから取り出した要素の変数名 : ${コレクションの変数名}">です。

  • テンプレート
<tr th:each="user : ${userList}" th:object="${user}"><td th:text="*{id}">111</td><td th:text="*{name}">Yumi Wakatsuki</td></tr>
  • レスポンスされるHTML
<tr><td>1</td><td>User1</td></tr><tr><td>2</td><td>User2</td></tr><tr><td>3</td><td>User3</td></tr>

僕もたまにやってしまうのですが、<c:forEach>の感覚で使っていると、こんな書き方をしちゃいます。

  • テンプレート
<table th:each="user : ${userList}"><tr th:object="${user}"><td th:text="*{id}">111</td><td th:text="*{name}">Yumi Wakatsuki</td></tr></table>

こう書いてしまうと、<table>要素自体が繰り返されるので注意してください。th:eachは、あくまで繰り返したい要素自身に付加します。

その他の記法

ユーテリティオブジェクト(#listsなど)

変数式などの中で、ユーティリティオブジェクトを呼ばれるものを使うことができます。

ユーテリティオブジェクトは、変数式などの中で#オブジェクト名.メソッド名(引数)で利用します。

Thymeleafには、あらかじめいくつかのユーティティオブジェクトが定義されています。

#listsはその1つで、リストに関するメソッドをいくつか持っています。

#lists.isEmpty()メソッドは、引数で渡されたリストが、nullまたは要素数ゼロの場合にtrueを返します。

下記の場合は、th:unlessと組み合わせて、userListが「nullまたは要素数ゼロ」でない場合に<table>要素を出力しています。

  • テンプレート
<tableborder="1" th:unless="${#lists.isEmpty(userList)}">
    ...
</table>
  • レスポンスされるHTML
<tableborder="1">
    ...
</table>

他にも色々なメソッドやユーティティオブジェクトがあるので、詳細は公式ドキュメントの下記のページを確認してみてください。

http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf_ja.html#appendix-b-expression-utility-objects

ちなみに、ユーティティオブジェクトは自作も可能です。

多分、SpringでThymeleafを使っていると、#fieldsというユーティティオブジェクトが見つかると思います。

これは素のThymeleafのものではなく、thymeleaf-spring4*2というライブラリ側が提供しているユーティティオブジェクトです。

コメント(<!--/* */-->

普通のHTMLコメント(<!-- -->)とすると、レスポンスされるHTMLにこのコメントが含まれてしまいます。

レスポンスされるHTMLに含めたくないコメントは、<!--/* */-->で書きます。

Thymeleafは、<!--/*から*/-->までをコメントとして認識し、テンプレートを解釈する時にこれらで挟まれた部分を無視します。

これを応用すると、こんなことが可能です。

<tr th:each="user : ${userList}" th:object="${user}"><td th:text="*{id}">111</td><td th:text="*{name}">Yumi Wakatsuki</td></tr><!--/*--><tr><td>222</td><td>Reika Sakurai</td></tr><tr><td>333</td><td>Erika Ikuta</td></tr><!--*/-->

th:eachで繰り返しを書く時、ブラウザで直接開いた時も、複数件のデータが見えるようにします。

上記で言うと、222番や333番の人は、ブラウザで直接開いたときは見えるのですが、サーバー上で実行したときは、<!--/**/-->で挟まれているので、この部分は無視されます。

さらに勉強するための参考資料

以上、最低限必要な機能を紹介していきました。

Thymeleafに興味を持って、さらに勉強されたい方は、下記の資料を読んでみましょう。

まずは、@bufferingsさんの資料を読んで、一通りの機能を把握しましょう。

Welcome Thymeleaf 3.0! #jjug_ccc #ccc_f2 // Speaker Deck

合わせて、公式ドキュメントも確認しておきましょう。

Tutorial: Using Thymeleaf

@bufferingsさんが翻訳された日本語版もあります。Thymeleaf 2.xの頃のドキュメントですが、あまり大きくは変わっていません。

Tutorial: Using Thymeleaf (ja)

SpringでThymeleafを使うという人は、「Spring徹底入門」を読みましょう。

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発(株式会社NTTデータ) | 翔泳社の本

Java EEで Thymeleafを使うという人は、僕のスライドを読んでみてください。

Java EEアクションベースMVC入門 #jjug_ccc #ccc_cd4 // Speaker Deck

それでは、Enjoy Thymeleaf!!

*1:正確には、Thymeleaf-Spring4というライブラリが提供しているクラスをBean定義します。詳しくはhttps://github.com/MasatoshiTada/spring4-thymeleaf/blob/master/src/main/java/com/example/web/WebMvcConfig.java

*2:ちなみに、thymeleaf-spring4はThymeleaf作者が自ら開発されています

ThymeleafでApache Shiroを使うためのライブラリを作ってみた

$
0
0

この記事は?

Java EE Advent Calendar 2016の19日目です。

昨日の記事は@khasunumaさんの「MicroProfile によるアプリケーション開発」でした。明日は@emaggameさんです。

今回は、以前@n_agetsuさんが紹介されていたApache Shiroというセキュリティフレームワークを、Thymeleafで使ってみました。

Apache Shiro を使ってみました - 見習いプログラミング日記

上妻さんのGitHubのサンプルをforkして、ビューをJSPからThymeleafに書き換えました。

合わせて、ThymeleafでApache Shiroを使うためのライブラリを作ってみました。

ソースコードGitHubにあります。

  • ThymeleafのApache Shiro用Dialect

GitHub - MasatoshiTada/thymeleaf-extras-shiro

  • 上妻さんのサンプルをThymeleafに移植したもの

GitHub - MasatoshiTada/ShiroSample: Apache Shiro 1.2 JDBC Realm sample

Dialectとは

上妻さんのブログでも紹介されている通り、Apache ShiroにはJSPカスタムタグが用意されています(タグの一覧はこちら)。

今回は、これらのJSPカスタムタグと似たようなものを、Thymeleafで作成しました。

Thymeleafといえば、タグの中にth:で始まる属性を記述していくのが特徴です。これらの属性は、自作することも可能です。

作成できるものは、属性の他、タグやユーティリティオブジェクト*1などです。

Thymeleafでは、これらを1つにまとめて「Dialect」と呼ばれます。

Dialectを自作する方法は、Thymeleaf公式Webサイトに公開されています。

Extending Thymeleaf

条件によって表示/非表示を切り替える属性を作る

Apache ShiroのJSPカスタムタグは、認証済み/認証済みでない等の条件によって、タグで挟んだ部分を表示する/しないを切り替えるものがほとんどです。

<%-- このタグで挟まれた部分はログイン中のみ表示される --%><shiro:authenticated><h3>Hello, <shiro:principal/></h3><formaction="/ShiroSample/users/logout"method="post"><divclass="form-group"><buttontype="submit"id="logout-button"class="btn btn-primary">logout</button></div></form></shiro:authenticated>

この<shiro:authenticated>タグを、Thymeleafの属性で下記のように作り変えてみました。(<shiro:principal>タグについては後述します)

  • Thymeleafの場合
<!--/* この属性で挟まれた部分はログイン中のみ表示される */--><div shiro:authenticated><h3>Hello, <span shiro:principal>foo@sample.com</span></h3><form th:action="@{/users/logout}"action="./index.html"method="post"><divclass="form-group"><buttontype="submit"id="logout-button"class="btn btn-primary">logout</button></div></form></div>

shiro:authenticated属性は、今回僕が作成したものです。機能はJSPカスタムタグと同じです。

条件によって表示する/しないを切り替える属性は、ThymeleafのAbstractStandardConditionalVisibilityTagProcessorクラスを継承すれば、簡単に作成できます。

このクラスにisVisible()という抽象メソッドが用意されているので、これをオーバーライドするだけです。

  • 全属性の親クラス
publicabstractclass AbstractSecureAttributeProcessor extends AbstractStandardConditionalVisibilityTagProcessor {

    publicstaticfinalint ATTR_PRECEDENCE = 300;

    public AbstractSecureAttributeProcessor(String dialectPrefix, String attrName) {
        super(TemplateMode.HTML, dialectPrefix, attrName, ATTR_PRECEDENCE);
    }

    protectedfinal Subject getSubject() {
        return SecurityUtils.getSubject();
    }

    protectedabstractboolean isVisible(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName, String attributeValue);
}
  • 認証済みの時のみ表示する属性
publicclass AuthenticatedAttributeProcessor extends AbstractSecureAttributeProcessor {

    /** HTMLで指定する属性名 */privatestaticfinal String ATTR_NAME = "authenticated";

    public AuthenticatedAttributeProcessor(String dialectPrefix) {
        super(dialectPrefix, ATTR_NAME);
    }

    /**     *認証済みであればtrue*/@Overrideprotectedboolean isVisible(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName, String attributeValue) {
        return getSubject() != null&& getSubject().isAuthenticated();
    }

}

親クラスを作っているのは、ShiroのJSPカスタムタグのソースコードを参考にしました。

AbstractStandardConditionalVisibilityTagProcessorクラスは、前述のドキュメントには書かれていないのですが、Spring Security用のThymeleaf拡張のソースコードを読んで知りました。

他にも、ロールの有無やパーミッションの有無で表示/非表示を切り替える属性を作ったのですが、すべて同じ作り方です。詳細はGitHubをご覧ください。

値を表示する属性を作る

さて、ShiroのJSPカスタムタグの中で、1つだけ役割が違うのが<shiro:principal>タグです。これは、ログイン中のユーザー名を表示するタグです。

<h3>Hello, <shiro:principal/></h3>
  • Thymeleafの場合
<h3>Hello, <span shiro:principal>foo@sample.com</span></h3>

値を表示する属性は、 ThymeleafのAbstractAttributeTagProcessorクラスを継承し、doProcess()メソッドをオーバーライドして作成します。

publicclass PrincipalAttributeProcessor extends AbstractAttributeTagProcessor {

    privatestaticfinal String ATTR_NAME = "principal";

    public PrincipalAttributeProcessor(String dialectPrefix) {
        super(TemplateMode.HTML, dialectPrefix, null, false, ATTR_NAME, true, 1000, true);
    }

    /**     *認証済みであればtrue*/protectedboolean isAuthenticated() {
        return getSubject() != null&& getSubject().isAuthenticated();
    }

    @Overrideprotectedvoid doProcess(ITemplateContext context,
                             IProcessableElementTag tag,
                             AttributeName attributeName,
                             String attributeValue,
                             IElementTagStructureHandler structureHandler) {
        String name = isAuthenticated()
                ? getSubject().getPrincipal().toString()  // ログイン済みならばユーザー名
                : "GUEST!!!";  // ログイン済みでなければ"GUEST!!!"を代替のユーザー名とする// 値を出力する
        structureHandler.setBody(HtmlEscape.escapeHtml5(name), false);
    }
}

ちょっと長いですが、値を出力しているのは、最後の行のstructureHandler.setBody()です。

作った属性をまとめて、1つのDialectを定義する

publicclass ShiroDialect extends AbstractProcessorDialect {

    privatestaticfinal String DIALECT_NAME = "Shiro Dialect";

    public ShiroDialect() {
        super(DIALECT_NAME, "shiro", StandardDialect.PROCESSOR_PRECEDENCE);
    }

    @Overridepublic Set<IProcessor> getProcessors(String dialectPrefix) {
        final Set<IProcessor> processors = new HashSet<>();
        processors.add(new GuestAttributeProcessor(dialectPrefix));
        processors.add(new NotAuthenticatedAttributeProcessor(dialectPrefix));
        processors.add(new UserAttributeProcessor(dialectPrefix));
        processors.add(new AuthenticatedAttributeProcessor(dialectPrefix));
        processors.add(new HasRoleAttributeProcessor(dialectPrefix));
        processors.add(new LacksRoleAttributeProcessor(dialectPrefix));
        processors.add(new PrincipalAttributeProcessor(dialectPrefix));
        processors.add(new HasAnyRoleAttributeProcessor(dialectPrefix));
        processors.add(new HasPermissionAttributeProcessor(dialectPrefix));
        processors.add(new LacksPermissionAttributeProcessor(dialectPrefix));
        return processors;
    }

}

AbstractProcessorDialectクラスを継承して、getProcessors()メソッドをオーバーライドします。

このメソッドの中で、作成した属性を表すクラスをインスタンス化して、すべてSetに格納して返します。

IntelliJEclipseで属性の補完ができるようにする

この作業は必須ではないのですが、やっておくと便利です。

src/main/resources配下*2に、下記のようなXMLを作成します。

<?xml version="1.0" encoding="UTF-8"?><dialect xmlns="http://www.thymeleaf.org/extras/dialect"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.thymeleaf.org/extras/dialect http://www.thymeleaf.org/xsd/thymeleaf-extras-dialect-2.1.xsd"prefix="shiro"namespace-uri="http://suke_masa.com/thymeleaf/shiro"namespace-strict="false"class="com.suke_masa.thymeleaf.extras.shiro.dialect.ShiroDialect"><attribute-processorname="authentication"class="com.suke_masa.thymeleaf.extras.shiro.dialect.processor.AuthenticatedAttributeProcessor"><documentationreference="authentication attribute"/></attribute-processor><attribute-processorname="principal"class="com.suke_masa.thymeleaf.extras.shiro.dialect.processor.PrincipalAttributeProcessor"><documentationreference="principal attribute"/></attribute-processor><!-- 一部省略 --></dialect>

これを作っておくと、このDialectを利用するときに、IntelliJEclipse(Thymeleafプラグイン必須)で属性の補完が効くようになります。

f:id:MasatoshiTada:20161219105028p:plain

作成したDialectを使う

TemplateEngineクラスのaddDialect()メソッドで、作成したDialectを追加します。

@Providerpublicclass ThymeleafTemplateProcessor extends AbstractTemplateProcessor<String> {

    @Contextprivate HttpServletRequest httpServletRequest;
    @Contextprivate HttpServletResponse httpServletResponse;

    private TemplateEngine templateEngine;

    @Injectpublic ThymeleafTemplateProcessor(Configuration config, ServletContext servletContext) {
        super(config, servletContext, "html", "html");
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
        templateResolver.setPrefix((String) config.getProperty(MvcFeature.TEMPLATE_BASE_PATH));
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateEngine = new TemplateEngine();

        // 作成したDialectを追加する
        templateEngine.addDialect(new ShiroDialect());
        templateEngine.setTemplateResolver(templateResolver);
    }

    // 以下省略

まとめ

  • AbstractStandardConditionalVisibilityTagProcessorを継承して、条件で表示/非表示を切り替える属性を作る
  • AbstractAttributeTagProcessorを継承して、値を出力する属性を作る
  • AbstractProcessorDialectを継承してDialectを作成し、作った属性を1つにまとめる
  • XMLを作成して、IDEで補完が効くようにする
  • TemplateEngineクラスのaddDialect()メソッドで、作成したDialectを追加する

参考資料

Apache Shiroのミニブック

Apache Shiroカスタムタグのソースコード

thymeleaf-extras-springsecurityのソースコード

Payaraのバグを報告してみよう

$
0
0

この記事は?

Payara Advent Calendar 2016の22日目です。

Payaraは、GitHub上でオープンソースで開発されています。Payara開発チームは、誰でもGitHubのIssueに書き込んでバグ報告してくれてOK、というスタンスをとっています。

僕は過去2回*1バグを報告し、修正してもらうことができました。

403 error occurs when Form-Authentication succeeded PAYARA-1244 · Issue #1213 · payara/Payara · GitHub

Payara does NOT rollback when RuntimeException occurs in CDI @Transactional method using JDBC · Issue #505 · payara/Payara · GitHub*2*3

今回は、修正してもらいやすいIssueの書き方について、僕が自分なりに気をつけていることをご紹介します。

Payaraの今使用しているバージョン・最新バージョン・過去のバージョンで比較する

今お使いのPayaraは最新バージョンでしょうか?もしそうでなければ、まずはPayaraの最新バージョンで動かしてみましょう。

Payaraは四半期に1回リリースされており、積極的にバグ修正や機能追加が行われているため、もしかしたらバグが修正されているかもしれません。

もし、最新バージョンで動けばそれでいい*4のですが、もし最新バージョンにしても問題が解決しなかったり、そもそも今お使いのものが既に最新バージョンであれば、1つ前など過去のバージョンのPayaraで試してみましょう。

過去のバージョンで期待通りに動作すれば、最新バージョン特有のバグの可能性があります。もし、過去のバージョンでも動作しなければ、以前から潜在していたバグの可能性があります。

余談ですが、Payara公式サイトからのダウンロードは、時とネットワーク環境にもよるのですが、めっちゃ遅いことが多いです(--;

僕は、過去にダウンロードしたPayaraのZIPファイルは、なるべく保存しています。

バグが再現する最小限のサンプルアプリを作り、GitHubにアップする

Payara開発チームは主にイギリスの方々なので、言語は英語です。英語でIssueを書くのは結構大変です。僕もまだまだ素早く正確に書くことができません(^^;

しかし、我々の共通言語であるJava言語であれば、英語圏の方を相手にしても、意図は明確に伝えられるはずです。

なので、バグが再現するサンプルアプリを作りましょう。さらにそれをGitHubにアップすれば、すぐにPayara開発チームに確認してもらうことができます。

このサンプルアプリは、Payara開発チームにバグを伝えることが目的なので、不要な機能は作らず、本当にバグが再現するだけの最小限のアプリにしましょう。

また、この最小限サンプルを作っていくことで、自分の中でも「どこがバグっぽいんだろう?」ということが明確になり、よりIssueを書きやすくなります。

設定はスクリプト化して、サンプルアプリと一緒にGitHubにアップする

GlassFish/Payaraの設定は、asadminコマンドまたはブラウザで開ける管理コンソールで行います。

管理コンソールはGUIで設定できるので非常に便利な反面、同じ設定手順を再現するのに時間がかかったり、打ち間違いなどで設定をミスする可能性があります。

よって、単純な設定ミスだったのか、設定は合っていて本当にバグだったのかが、自分にもPayara開発チームにも分かりづらくなってしまいます。

なので、設定はできる限りasadminコマンドで行い、それを1つのシェルスクリプトにまとめましょう。それを最小限サンプルと一緒のプロジェクトにまとめてGitHubにアップしてしまえば*5、Payara開発チームにも使ってもらえます。

また、スクリプト化することで、Payaraの複数バージョンでの確認もやりやすくなります。PayaraのZIPを展開して、スクリプトを実行するだけで設定が完了しますので、時間もかからないし、設定をミスする心配が少なくなります。

asadminコマンドについては、蓮沼さんのブログうらがみさんのブログを確認しましょう!

発生する現象とその再現手順を明確にIssueに書く

さて、ここまで準備が完了すれば、あとは頑張ってIssueを書くだけです。

どうしてもここは英語がついて回りますが、「どんな現象が発生するのか?」「最小限アプリを使って、どのような手順でその現象を再現できるか?」の2点を外さなければ大丈夫です。

これをコードやスクリーンショットを交えて書けば、英語の文章も少なく済みます。もちろん、GitHubにアップしたサンプルアプルのURLも忘れずに、Issueの最初の方で書いておきましょう。

また、最近はIssueのテンプレートが作成されて、使っているPayara・OS・JDKのバージョンを書く欄がありますので、これも埋めてください。

Payaraに貢献しよう!

Payaraを利用している方、もし何かバグっぽいものに遭遇したら、ぜひIssueを書いてみてください。

それにより、PayaraそしてGlassFishがより良いものとなっていきます。そしてそれは、Java EE全体への貢献にもつながるはずです。

それでは、Enjoy Payara & Java EE!!

*1:本当は3回なんですが、僕の勘違いだったことが1回あったため、含めていません(^^;

*2:こちらのバグは、僕が発見したものではなく、僕はIssueを書いただけです。詳細はこちらのコメント欄へ

*3:しかし、「Payara does not rollback」は我ながらカッコ悪いですね・・・。正しくは「Rollback does not work」とかでしょうか?

*4:よくない場合もあると思いますが

*5:パスワードなどの機密情報はなるべく伏せてアップしてください


マイクロサービスアーキテクチャ読書会 資料一覧 #MSA読書会

読書録:ロッシェル・カップ「日本企業の社員は、なぜこんなにもモチベーションが低いのか?」

$
0
0

きっかけ

www.cm-publishing.co.jp

この本というかロッシェル・カップさんを知ったのは、Twitterマイクロソフト牛尾さんをフォローしていて、牛尾さんが色んな所でロッシェルさんと発表されたのを見たのがきっかけだった。

いちおう中小企業診断士という資格を持っていて(さいきん休業したけど)、経営・組織・マネジメントなどにも興味がある分野なので、この本を読んでみることにした。新しいビジネス書を読むのは久しぶりだった。

最初はKindleの試し読みで第1章だけ読んだのだが、とても良かったので図書館で借りることにした。

読んでいて辛い

これが率直な感想。なぜ辛いのかというと、これまでの9年間の社会人生活の中でずっと思ってきたことが網羅されていて、共感できることがあまりに多すぎたからだ。どこがどう共感できたかは、差し障りがありそうなのでここには書かない。

年功序列は若年層にも中高年にもモチベーションの低下を招く

あまり給与のことは多くは書かれていないので、ここは自分が思ったこと。

年功序列だと、若年層はどれだけ頑張っても給料が上がらないから、モチベーションが低下する。

しかし実は、年功序列は中高年の方のためにも、良くないのではないか。完全に想像だけど。年功序列っていうけど、どこかの年齢(たぶん40代くらい)で昇給は頭打ちになるから。

年齢にかかわらず、頑張り具合で給料が大幅で上下したほうが、モチベーションがキープできるんじゃないかな。

企業のマネジメントだけの問題ではない

最後の第8章のみ、企業向けのメッセージではなく、社員向けのメッセージになっている。

この本では、主に日本企業のマネジメントに対する提言が書かれているが、われわれ社員側の意識も大切だと思う。

マネジメント層だって人間だ。完璧ではない。社員も多様だし、全員が満足して働ける会社なんてなかなか作れない。

会社への不平不満をただ並べるばかりでは、何も改善しない。会社のためにも自分のためにもならない。そんな暇があったら、いま自分ができることを精一杯やることが大事なんじゃないか。

自分で自分の目標を立て、自分のスキルや経験を磨く術を考える。業後の勉強でもいいし、業務でも興味がある仕事に積極的に手を挙げる。

勉強会に出てみたり、ブログ書いてみたり、勉強会に登壇してみたり、そこで色んな人と交流してみたり。ITってこれがやりやすいからいい。

これって、自分自身のためにもなるし、自分のスキルが上がれば、それが結果的に会社のためにもなるんじゃないかな。少なくとも、この30半ばのおっさんはそう思って日々仕事してます。

この第8章からは、とても勇気をもらった。

まとめ

久々に、いいビジネス書を読んだ。ビジネス書から勇気をもらったのは、ドラッカー以外でははじめてだ。

働く人、マネジメントの人、すべての人におすすめしたい。

JJUG CCC 2017 Springにスポンサー枠で出てきました! #jjug_ccc

$
0
0

今回もJJUG CCCに登壇しました。

これまでは普通にCfPに応募していたのですが、今回は会社とも相談して、初めてスポンサー枠として登壇しました!

今回で連続出場記録は7回連続7回。今後も記録を伸ばしていきたいです。

今回の登壇テーマ

いろいろ考えたんですが、最近はRESTやMicroservices関連の業務も多いので、その文脈で出てくることの多いセキュリティプロコトル「OAuth 2.0」をテーマとしました。

OAuth 2.0対応のライブラリ「Apache Oltu」+Payara MicroProfileを利用してサンプルアプリを作り、OAuth 2.0の仕様・HTTPS通信の様子・Javaプログラムのサンプルをご紹介しました。

120名部屋が満員で、後ろに追加の椅子も出されたくらい大盛況でした!聞いてくださった皆様、本当にありがとうございます。

アンケート評価はこちらです。

f:id:MasatoshiTada:20170522201617p:plain

f:id:MasatoshiTada:20170522201625p:plain

「難しい」という評価が多数派でした。OAuth 2.0そのものが難易度高めなのですが、それを如何に分かりやすく伝えるかがトレーナーの腕の見せどころなので、反省しきりです。

スライドの順番とか、もっと図を多めにするとか、Javaコードを省いてHTTPSでのやり取りにフォーカスするとか、改善の余地はあると思います。

新人研修時期が落ち着いたら社内勉強会でも発表したいので、そのときに修正しようかなあ・・・。

togetterまとめはこちら。

togetter.com

後半のほうに書いてありますが、緊張のあまりデモの準備を忘れてしまい、最後にやったはいいが動かなかったという・・・(^^;

これも反省です。

聴講したセッション

非機能要件とSpring Boot (@garbagetownさん)

IPAが公開している非機能要求グレード(http://www.ipa.go.jp/sec/softwareengineering/reports/20100416.html)の項目のうち、Spring Boot Actuator・Spring Security・Spring Data JPAなどでどのような項目をどのようにしてカバーできるかという解説でした。

研修やってるだけだと、あまり意識しないこともあるので、とても参考になりました。

Java EE 8 and its latest update (David Delabasseeさん)

Spring業務が多くなったとは言えJava EE屋さんでもあるので、このセッションは外せませんでした。

CDI 2.0・JAX-RS 2.1・Servlet 4.0など、新機能の解説が主でした。EE 9の話は特に無し。2018年にJava EE 8対応のWebLogic Serverが出る予定と言うのが、1番のサプライズでした。

今年7月にJava EE 8、出るのかなあ・・・。

How to use MicroProfile and a way to rebirth Japanese enterprise computing (@khasunumaさん)

我らがGlassFishユーザー会会長・蓮沼さんのセッションです。内容は主にMicroProfile(http://microprofile.io)でした。数少ないJava EE関連のセッションです(僕も頑張ってJava EEでサンプル作りました)。

最後に質問タイムがあったので、僕は「MicroProfileとJava EEの統合はあり得ると思いますか?」と質問しました。

MicroProfileでは、設立当初から「Oracleが友好的であれば歓迎する」(表現違ったかも?)というスタンスだそうです。

さて、これもどうなることやら・・・。

ヤフーの広告レポートシステムをSpring Cloud Stream化するまで (Yahoo! Japanさん)

広告レポートシステムのアーキテクチャを、PHPPerl→Spring Batch→Spring Cloud Streamという歴史的流れを追って解説していました。

DBからポーリングするのではなく、イベント駆動にすることで負荷を減らしパフォーマンスを向上させたのが興味深かったです。

Java x Arduinoで始めるIoT / フィジカルコンピューティング (@yusukeさん)

正直、自分のセッションで力尽きてて、あまり記憶がありません・・・(^^;

JavaプログラムでLEDが光ったりタイミングを変更できたりTwitter4J使ってツイートできたり、とても面白かったのを覚えています。

感想など

ついに参加者が1000人を超えたとのこと。すごすぎるなあ・・・。

今回はセッションが45分間になり、その分だけ休憩時間が15分になりました。なので、休憩中のお手洗いなどは余裕ができました。

人数が多くなった分、通路が混雑したりということはありましたが、通路を一方通行にしたり、部屋によって休憩時間を少しズラしたりすることで、ある程度解決できるのではと思います(アンケートに記入済み)。

会場の変更という手もあるかとは思いますが、更に広い会場となると値段も高くなる(現状で既に数百万円レベル)し、運営も難しくなるでしょう。うーむ、難しいですね・・・

運営側でない自分ができる貢献は、登壇やスポンサー枠の他、アンケートやブログなどでの問題点の発見と解決策の提案かなあ、と思っていますし、非力ながらも貢献を続けたいと思っています。

幹事およびボランティアスタッフの皆様、いつもありがとうございます。お疲れ様でした!

「Spring Bootの本当の理解ポイント」というタイトルでJJUG CCC 2017 Fallに登壇してきました! #jjug_ccc

$
0
0

登壇してきた

www.slideshare.net

今回で8回連続8回目の登壇になりました。今後も記録を伸ばしていきたいです。

スライドもかなり多くの方々に読んでいただけているようで、現時点で4100viewsを超えています。

アンケートの結果はこちら。ご満足いただけたようで何より。

f:id:MasatoshiTada:20171123090142p:plain

f:id:MasatoshiTada:20171123090205p:plain

何故この内容にしたか

最近、Java EE研修のお客様はめっきり減り😅、ほぼSpringの研修ばかりやっています。

その中で実感しているのは、Spring BootでSpringに初めて触れたという方が多いと言うことです。

Spring BootはSpringの面倒な部分を隠蔽するので、一見便利なのですが、その面倒な部分を理解していないと、カスタマイズやトラブルシュートが出来ません。

また、世の中の「Spring Bootのブログ」を読んでいると「ん?コレ、BootじゃなくてSpringの話だよね?」と思う記事が非常に多いです。

そういった世の中に警鐘を鳴らしたいと思って、今回のテーマを選びました。

やってどうだったか

前述のとおり8回出させていただきましたが、ようやっと自分の立ち位置というか、自分に求められているものが分かってきたような気がします。

僕は現役のエンジニアではありません。そんな自分が、CCCに参加されるエンジニアの皆さんに何を提供できるのか、迷った時期もありました。

僕には、「現場で使ってこうだったよ!」とか「こんなテクニックがあるよ!」という話はできないからです。

しかし今回のように、中・上級者の方は分かっているけど暗黙知になってしまっている事柄を、整理して分かりやすく伝える、そのための資料を作る、ということなら僕にも出来ます。

初・中級者の方にとっては知らなかったことを知っていただけるし、中・上級者の方には人に説明するための資料や説明手順を提供できます。

次回以降もこんなテーマを見つけてやっていきたいと思います。

この4年間をちょっと振り返る

僕の初参加、そして初登壇は2014 Springでした。

正直、その頃はどのセッションを聞いてもサッパリ分かりませんでした。でも、3回目くらいから、ようやっと徐々に分かるようになってきました。

何年も前の内容が、今になって役に立つことも結構よくあります。例えば、今はMicroservices関連のこともやっているのですが、@nabedgeさんの12 Factorの資料は今になってとても参考になっています。キーワードだけでも知っているといないではだいぶ違います。

www.slideshare.net

登壇することで、自分の技術力がかなり上がったようにも感じています。資料作りのときにメッチャ調べなきゃいけないし、それは結構しんどい工程でもあります。しかし、それを何回も繰り返すことで、自分の知識が整理されたり、知らなかったことを知れたりして、自分の技術力がどんどん上がっていきます。

あと何より、色んな人との繋がりができたのが大きいですね。発表者になることで、声をかけてもらう回数が増えました。自己紹介が手短で済む(「今日○○で登壇した多田と申します」とか)ので、こちらから他の登壇者の方にお声がけするのも飛躍的に楽になります。懇親会でボッチにならずに楽しめるのは本当に嬉しい!w

ブログやTwitterでしか知らなかった方や、登壇者として「この人すごいなー!」としか思えなかった雲上の人ともお話できて、更に色んな技術情報が入ってきます。そこで、自分の理解が合っていたことを再確認できたり、間違っていたら修正できたり、全く知らなかったことを知れたりします。

自分にとって、JJUG CCCは無くてはならないものになりつつあります。JJUG CCCが無かったら、今の自分は無いですね。

全体的な感想

前回あった会場混雑の問題が、一方通行の導入や分かりやすいサインなどで解消されていました!参加者数も絞ったのかな?また、今回は参加できなかったのですが、アンカンファレンスなど新しい取り組みもありました。

費用面や運営面など、規模の拡大はこれ以上はなかなか難しいでしょうね・・・。

イチ参加者として、個人的にはこれくらいの規模が上限かな・・・と思います。これ以上規模が大きくなると、同時並行のセッション数が多くなるので、聴き逃してしまうセッションが多くなってしまうからです。

JJUG幹事の皆さん、ボランティアスタッフの皆さん、いつもありがとうございます。

僕もスピーカーとして、CCCへのコントリビュートを続けていきたいと思います!

はじめてのSpringOne 事前準備編

$
0
0

初の海外カンファレンス参加!

エンジニアにとって、海外カンファレンスに参加することは憧れの1つかと思います。Javaエンジニアなら有名どころはJavaOneでしょう。

今回いろいろな幸運もあり、Pivotal社が主催しているSpringOne Platformに参加することになりました!

Spring Framework / Spring Boot / Spring Cloud / Cloud Foundryなど、Pivotalがリードしているテクノロジーの最新情報が聞けますし、最近は仕事でもこのあたりの技術を触ることが多いので、機会に乗って行くことにしました。

カンファレンスに申し込もう

SpringOneの公式ページから申し込めます。

https://2017.springoneplatform.io/ehome/s1p/registration2017.springoneplatform.io

お値段は1700ドルと安くはないのですが、早めに申し込むとやや安めになります。

また、更に安くなるディスカウントコードというのもあります。コードの取得方法は、興味があればTwitter DMや対面で聞いてください。

プレカンファレンストレーニングを受けてみよう

SpringOneは計3日間なのですが、その直前の2日間で特別なトレーニング(研修)を受けることが出来ます。

springoneplatform.io

2日間で700ドルと、通常のトレーニングに比べるととてもお得な値段になっています(もちろん、宿泊費とかは追加でかかりますが)。

内容は、僕も実施しているPivotal認定トレーニングとほぼ同じなのですが、Spring Boot 2.0やSpring 5など、最新技術が演習付きで学習できるのが特徴です。

僕は今回、「What's new in Spring 5」を受講することにしました。これを担当される講師の方が、いつも使っている認定テキストを作っているマスタートレーナーの方らしく、とても楽しみです!

宿泊などを手配しよう

必要なのはホテル・飛行機・保険の3つです。

今回はHISでまとめて手配しちゃいましたが、個別に手配してもよかったかな・・・と思います。

ホテルの注意点としては、危険な地域は避けることです。今回の会場であるサンフランシスコは比較的治安は良いようですが、それでも一般人は入るべきでない地域もあるようです。

危険な地域は、その地域に詳しい人(サンフランシスコならJavaOne経験者など)に相談するのがいいでしょう。もしくは、「地球の歩き方」という本に付属の地図に治安の良くない地域が書かれています。

地球の歩き方 ガイドブック B04 サンフランシスコとシリコンバレー2018年〜2019年版

飛行機は今回、JALの羽田・サンフランシスコ直通便にしました。香港経由便などを利用するともっと安くなるらしいのですが、僕はあまり海外旅行の経験が多くないので、万が一トラブルがあった場合や体力的なことを考えて、直通便にしました。

あと、HISなどを経由せず航空会社のWebサイトから直接申し込んだ方が、座席指定が出来たりメリットが大きいかな、と思いました。僕は体がデカイので、なるべく通路側の席が良かったりしますので・・・。

渡航手続きをしよう

ESTA

アメリカに短期間渡航する場合、ビザの取得は必要ありません。その代わり、WebからESTAの事前登録が必要になります。

https://esta.cbp.dhs.gov/esta/application.html?execution=e1s1

期限は渡航72時間前までらしいですが、時間がかかる場合もあるそうなので、なるべく早く登録しておいたほうがいいでしょう。

英語を勉強しよう

海外カンファレンスですから、スピーカーは全員英語で発表します。行くからには内容をなるべく理解したいので、英語も改めて勉強することにしました。

TOEIC Listening & Reading

まずはリスニング。TOEICは昨年受けたのですが、リスニングは全然聞き取れた気がしなかったので、改めて受験することにしました。

やったことは、去年買った単語集を改めてCDを聞きながら覚え直し、

CD-ROM付 改訂版 TOEIC(R)TEST 英単語 出るとこだけ!

新形式の問題集をやり直したことです。

公式 TOEIC Listening & Reading トレーニング リスニング編

公式 TOEIC Listening & Reading トレーニング リーディング編

公式TOEIC Listening & Reading 問題集2

おかげでだいぶ問題を聞き取れるようになり、スコアもかなり上がりました(リスニング390 -> 455)。

リーディングはちょっと下がっちゃったけど・・・😅(リーディング435 -> 405)

マンツーマン英会話

次にスピーキング。これを機会に、ガチで勉強することにしました。

会話力を上げるならマンツーマン英会話だろう、ということで、BerlitzとGabaを体験して前者に通うことにしました。

まあ、どちらも安くはないですね。。。ただ、ずっと外国人講師の方を相手に会話することを自分に強制できるので、とてもいい勉強になりました。

実際に向こうに行かないと分かりませんが、以前に比べれば話したいことがスッと出るようになった気がします。

いざ出発!

さて、明日夜の便で出発です!行ってきまーす!

はじめてのSpringOne 出発→到着編

$
0
0

無事にサンフランシスコに到着しました。今、夕食を食べ終わってホテルにいます。

飛行機

HISで、JALのサンフランシスコ直通便を確保していました。

羽田空港でチェックイン時に、スタッフの方から「座席のご希望はございますか?」と聞かれたので、通路側を希望したら変更できました。スタッフのお姉さんありがとう!帰りのときも聞いてみます。

8時間半くらいのフライトでしたが、ほとんど眠れず。。。出発前日も緊張であんまり眠れてないので、かなりしんどい。。。

サンフランシスコ国際空港に到着→入国審査

入国審査で「モスコーニセンターでのカンファレンスに参加します」と答えたら、「Business Letterはあるか?」と聞かれました。

字面では分かりますが、今の文脈で何を指しているのか分からなかったので「Sorry, I don't understand. What do you mean by "Letter"?」って聞き返したら何かバカにされたような・・・。

結局そのまま通されましたが、何だったんだろう。招待状とかのことを言ってたのかな?そんなもん無いんだけど・・・。

空港からダウンタウンに移動

BARTを使いました。

ここでトラブル発生。アテにしていたClipper(Pasmoみたいなやつ)の自販機が「Out of Service」。そして、普通の切符の買い方がよく分からない・・・😅

どうやら日本の電車の切符みたいに1回きりではなくて、プリペイド形式みたいですね。

前の座席にコワモテのお兄さん3人がデカイ声で喋っていて、正直怖かった・・・。

ホテルにチェックイン・・・!?

ユニオンスクエア近くのホテルにしました。しかし、ここでもトラブル発生。

到着したのが13:00くらい。チェックインが無事に済み、渡された書類を確認すると、ルームキーが入ってませんでした。

「Excuse me. Where is my room key?」と聞いたら、部屋は15時半にならないと使えないとのこと・・・。

しょうがないのでスーツケースだけ預け、観光に行くことにしました。預けたときも、「さっき預かってくれた人は偽の制服を来たスリなんじゃないか」と思って気が気でなかったです。(ちゃんと従業員用の部屋に入っていったので本物のスタッフさんだった)

フィッシャーマンズワーフへ

もともと行こうと思っていたフィッシャーマンズワーフへ行って時間をつぶすことにしました。

しかし、ここでもトラブル続き。移動に使おうと思っていたケーブルカーが激コミ。

f:id:MasatoshiTada:20171203122331j:plain

じゃあタクシーだ!と思って初めてUberアプリを使ったら謎のエラーで配車できない。なのにマップに従って乗り場に向かったら何だか怪しい雰囲気のところに行ってしまい引き返す・・・などなど。

この時点でもうだいぶ心が折れかけていて、率直に言えば「おうちかえりたい」気分でした。

でもまあ頑張っていこうと思い、Uberを使わず普通にタクシーを拾ってようやっとフィッシャーマンズワーフに着いたのでした。

Aquarium of the Bayという水族館に行ったのですが、来るまでのトラブルでもういっぱいいっぱいになっていて、内容があまり頭に入ってこなかった・・・。

ホテルのお部屋へ→晩ごはん

ホテルの部屋にようやっと入れ、安心して一息つけました。

晩ごはんは近くのステーキ屋さんへ。ジャンクな感じで美味しかったです。本当は更にベイクドポテトが付いてるんですが、食べきれないと思って外しました。

f:id:MasatoshiTada:20171203123718j:plain

お店はこちら。

Tad's Steakhouse | San Francisco

明日から

明日・明後日は2日間のプレスカンファレンストレーニングです。

Spring 5の新機能を学習してきます!

はじめてのSpringOne 体調不良からの病院編

$
0
0

12/3(日)・4(月)の2日間は、プレカンファレンストレーニングを受講する予定だったのですが、ここでもまたトラブル発生で、体調を崩し病院に行くことになってしまいました。(体調はすでに回復しています)

ある意味なかなか貴重な体験をしましたので、これから海外カンファレンスに行きたい方の参考のためにまとめておこうと思います。

サンフランシスコ到着初日の12/2(土)から、要点を時系列で書いていきます。

時系列

12/2(土) AM11:30

サンフランシスコ到着。飛行機での睡眠時間は2時間弱。ハイになっているからか、あまり眠気は感じなかった。この時は特に体調不良は感じなかった。

12/2(土) PM06:00

晩ごはん。ステーキを食べたくらいなので、この時も体調不良は感じず。

12/2(土) PM10:00

早めに就寝。ちょっと部屋が乾燥してるなーとは思っていた。

12/2(土) PM11:00

1時間ほどで目が覚める。部屋の乾燥のせいか、喉がイガイガした。もう一度寝てみる。

12/3(日) AM12:00

また1時間ほどで目が覚める。喉のイガイガが増した。もう一度寝てみようとしても眠れず。

部屋の乾燥がひどいので、フロントに電話して加湿器が無いか聞いてみたが、無いとの回答。

うーん、日本のホテルだとだいたい貸してくれるんだけどな・・・😅

バスタブにお湯を溜めてバスルームのドアを開けっ放しにするなど、思いつく限りの対策を行う。

12/3(日) AM05:00

多分この時間くらいに寝落ち。

12/3(日) AM07:00

スマホの目覚ましで起きる。喉のイガイガがめちゃくちゃ酷くなっていた。

手がとても冷たかった。

12/3(日) AM09:00

少ししんどさもあったが、予定通りSpringOne会場に向かい、プレカンファレンストレーニングを受講開始。

12/3(日) AM09:30

喉の痛みのほか、動悸・息苦しさ・微熱を感じ始める。内容が頭に入ってこない。(英語なのもあるけど)

12/3(日) AM10:30

体調がついに限界を迎える。周りの方に迷惑をかけるわけにもいかないので、同じ部屋にいたPivotalのスタッフの方に事情を説明し、泣く泣く途中退出。

歩いてホテルに戻る。(徒歩10分くらい)

12/3(日) PM12:00

少しホテルで休憩した後、コンシェルジュに「お医者さんを紹介してほしい」と相談。

日曜日なので開いてるかな・・・と心配していたが、近くに開いている病院があるとのこと。

コンシェルジュが病院に電話してくれた。自分は英語に自身がないと伝えたら、代わりに自分の症状などを伝えてくれた。マジ感謝。

自分からが「微熱(I have a slight fever)」「喉の痛み(I have a sore throat*1)」

今すぐ行けるとのことだったので、予約を取ってくれた。徒歩で2-3分の病院へGO。

12/3(日) PM12:30

病院へ。身分証明書としてパスポートを受付で見せる*2

受付票に名前・住所・簡単な症状を書く。

最初は看護師さん?による検査。そのあとお医者さんによる触診など。

お医者さんの英語は速いし単語が難しいので理解に苦労したけど、必要に応じてGoogle翻訳を使ってくれた。

こちらも、分からない医療用語(「普段からじんましんの薬を飲んでいます」とか)はGoogle翻訳を使って伝えた。

感染症などではなく、乾燥による喉の痛みとのこと。

薬を2種類もらい、ホテルへ戻る。(この時、たしかPM02:00くらい)

ちなみに、日本と違って薬局でもらう方式ではなく、病院で直接薬をくれた。

診療費+薬代で約300ドル。保険効かないので高いですが、旅行保険に入っていれば後日精算可能、なはず。

12/3(日) PM02:30

遅くなったけどお昼ごはん。

ホテルの近くはハンバーガーやピザやステーキのお店ばかり。体調悪いし喉も痛いし、そんなん食うてられん。

そこで、近くのスーパーマーケット「Walgreens」へ。サンドイッチやSushi(敢えて寿司とは書かない)もあるので病人にも優しい。

マグロ+アボカドの巻きSushi、カットフルーツのマンゴーやパイナップル、ヨーグルト、100%オレンジジュース、そして大量のミネラルウォーターを買い込む。

リュックには入り切らないのでレジ袋を所望。(「May I have one shopping bag?」で通じます)

部屋に戻ってSushiをmgmg。もらった薬を飲む。

日本から持ってきたカップ味噌汁も作ったが、沸かしたお湯がぬるくて美味しくなかった。

12/3(日) PM04:00

夜寝ることを考えると、加湿器は必須だった。

しんどさはあるが、近くに家電量販店があるか検索し、加湿器を買いに行くことを決意。

Google Mapで「サンフランシスコ 家電量販店」で検索すると、近くに「RazerStrore」と「Target Open House」の計2件がヒット。

やや近かったRazerHouseから行ってみた。ゲーム機しか置いてなかった。。。

次にTarget Open House(Mosconeのすぐ近く)へ。家電量販店というよりはホームセンターに近いかな?でも家電もそこそこ置いている。

店がメチャ広くて探すのに苦労したが、店員さんに「Where can I get a humidifier*3?」と聞きつつ見つけてゲット。値段は58ドルと安くはないが、命には換えられなかった。

12/3(日) PM05:00

ホテルへ戻って加湿器を設置。パワーが強い方を買ったので、これで十分そうだ。

12/3(日) PM07:00

晩ごはんは、近くの日本料理レストランで鍋焼きうどん。日本の鍋焼きうどんの再現性高し。

f:id:MasatoshiTada:20171205112059j:plain

12/3(日) PM09:00

寒気がする。これは熱が上がる予兆だ。

実際、しばらくすると逆に熱くなってきた。

12/3(日) PM10:00

不安を感じつつ就寝。

12/3(日) PM11:00

1時間で目が覚める。案の定、熱がメチャクチャ上がっている感じがする。

フロントに電話して体温計を所望するも「無い」との回答。ええい使えん。

ロキソニンなど日本から持ってきた市販薬はあるが、敢えて使わなかった。

自分の理解では、熱は勝手に上がるものではなく、何らかの理由があって自分の体が自ら熱を上げている(細菌を殺すとか)ので、解熱剤はあまり多用すべきでないと思ったからだ。あまりに長時間続くようだったらロキソニンを使おうと決めた。

2時間くらい、身体が冷めないように布団をかけながらネットサーフィンしつつ過ごしていると、だんだん汗をかくようになり、それに伴って熱が下がってきた。

頭もかなりボーッとしてたが、徐々にハッキリしてきた。

12/4(月) AM02:00

だいぶしんどさも軽くなってきたので、もう一度就寝。何回か起きたけど、そこそこ眠れた。

12/4(月) AM07:30

起床。喉の痛みはまだあるが、加湿器のおかげでだいぶマシになった。

だるさも少し残っているので、今日のプレカンファレンストレーニングも欠席した。無念・・・。

また、夜は前夜祭的なパーティーがあるのですが、これも欠席しました。

今日はWalgreensへの買い物以外はずっとホテルに居て、今に至ります。

ポイント

旅行保険大事!

健康保険が効かないので、医療費はメチャ高くなります。それを後日でも生産できるのは本当にありがたいです。

睡眠大事!

実は、緊張からか出発前日や飛行機内では、あまり眠れませんでした。

後々になってダメージが来ることがあるので、サプリメントや市販の睡眠薬などを活用すると良いかもしれません。

加湿器大事!

サンフランシスコは本当に乾燥しています。ホテルの部屋は空調の関係上、より乾燥しやすいです。

日本から持ってこれるなら、持ってくるべきと思います。しかも、なるべくパワーが強いやつ。

早めに誰かに相談を!

英語の不安もあるかと思いますが、ホテルのスタッフのどなたかにとにかく相談しましょう。何らかの対応はしてくれるはずです。

(僕のホテルの深夜担当フロントは本当に使えなかったけど・・・)

あとは、旅行保険に日本語OKの連絡先とかもあるはずなので、それを必ず確認しましょう。

Walgreens最強

食料品はなんでも揃っています。

Target Open House最強

日用品から家電までなんでも揃っています。

インターネッツ最強

Google翻訳Google Mapにはお世話になりました。スマホWiFi無かったら・・・と思うとゾッとします。

堂島庵最強

日本食を、けっこう違和感ない感じで提供してくれます。スタッフには日本語を話せる(というか日本人っぽい)方もいらっしゃいます。

100%オレンジジュース最強

米国のジュースって甘ったるいものが多いですが、100%オレンジジュースなら日本とほぼ同じです。日本でもおなじみのブランドも多いし。

最後に

会社の出張で来てるのに・・・という申し訳なさと、海外で体調を崩してしまったことへの不安と、周りに誰もいない心細さで、潰されそうになりました。

30すぎのOssanな僕ですが、一瞬本気で泣きそうになりました。

明日から、カンファレンスの本番です。体調を見ながら、休憩しつつ参加していきます。

*1:実は最初、自分は間違えて「throatache」と言ったんだけど、コンシェルジュが正しく「sore throat」と言い換えてくれた

*2:病院に限らず、クレジットカードを使うときなど「IDを見せてください」と言われることは多いので、パスポートは常時携帯必須

*3:ヒューミディファイアー。アクセントは「ミ」


Cloud Foundryを学習する方法

$
0
0

この記事について

この記事は、Cloud Foundry Advent Calendar 2017の15日目です。

Cloud Foundry(以下CF)は、日本国内でも広がりを見せていますね。ただ気になるのは、Cloud Foundryの学習手段がまだ少ないことです。

そこで今回は、これからCFを始めたい人向けに、どのように勉強すればいいかを僕なりに整理してご紹介していきます。

自己紹介

CF関連のブログを書くのは初めてなので、軽く自己紹介します。

多田真敏(ただまさとし)と言います。カサレアルという会社で、研修トレーナーをやっています。

もともとJava EESpring FrameworkなどサーバーサイドJavaを中心に担当していました(もちろん今もやってます)。

SpringについてはPivotal認定講師ということもあり、Pivotal Cloud Foundryの開発系トレーニングも、今年から始めています。

ということで、内容がどうしてもPivotal Cloud Foundry (以下PCF)寄りになってしまうのですが、OSSのCFでも共通する内容になるよう気をつけて書いていきます。

ハンズオン

まずはとにかく、触ってみることから始めましょう。Pivotalジャパンさんが、GitHubにハンズオン資料を公開されています。

github.com

元々はPivotalジャパンさんが無料セミナーで使っている資料なのですが、ご自分で学習する時に利用することは全く問題ありません。

もちろん、ここで利用しているCFはPCFなので PCF独自機能の紹介も含まれていますが、大半は元々のCFの内容なので、どのCFディストリビューションを使うにしても参考になる内容が多いです。

cfコマンドを使ったアプリケーションのデプロイやスケール、Blue/Greenデプロイを体験しましょう。

ハンズオンと並行して、資料にリンクが貼ってある下記のスライドも読みましょう。CFで何が出来るか、どんな仕組みかがざっくり理解できます。

www.slideshare.net

書籍

Amazonで「Cloud Foundry」で検索すると、洋書が実質3冊しかありません。日本語の本は皆無です。

https://www.amazon.co.jp/s/ref=nb_sb_noss_2?__mk_ja_JP=カタカナ&url=search-alias%3Daps&field-keywords=cloud+foundry

僕が購入したのは、Cloud Foundry: The Definitive Guide: Develop, Deploy, and Scaleという本です。

出版されたのが2017年5月と新しく、ほぼ現時点で最新の内容が紹介されています。内容はCloud Foundryの内部の仕組みやアーキテクチャが中心で、管理寄りですね。全体的に平易な英語でかかれており、とてもわかり易いです。

開発系の内容は、あまり多くありません。とりあえず、第3章Components、第6章Diego、第9章Buildpacks and Dockerだけでも読んでおくと良いでしょう。

コミュニティ

コミュニティの勉強会にも行ってみましょう!色んなエンジニアの方々のお話や、最新情報などを得られます。

www.meetup.com

paas.connpass.com

pivotal-japan.connpass.com

Eラーニング+資格

Cloud Foundry Foundation公式のEラーニングと資格があります。(ただし全部英語)

これらはもちろん有償です。Eラーニングが$299、資格試験が$300です。セットで購入すると割引で$499になるみたいです。

training.linuxfoundation.org

たまに激安セールしていることがあって、セットで半額みたいな値段で買えることがあります。

Twitterで@cloudfoundryをフォローしておくとセール情報が流れてくるので、ぜひフォローしておきましょう!

Eラーニングの内容については、CFだけでなくMicroservicesやCI/CD、Dockerなど様々な内容から構成されています。

資格試験については、まだ未受験なので何とも。。。😅

(実はこのアドベントカレンダーの日までに受験しようと思っていたのですが、諸般の事情で・・・)

試験時間が4時間という、かなりガッツリ系の資格です。もし受験された方がこの記事を読んでいたら、ぜひコメント欄で情報ください!

トレーニング+資格

PCFのトレーニングになりますが、僕がやっている「Pivotal Cloud Foundry Developer」という開発者向けトレーニングがあります。

Pivotal認定 Pivotal Cloud Foundry Developer | 株式会社カサレアル ラーニングサービス

Pivotal製のテキストですので全部英語ですが、講師である僕はすべて日本語でトレーニングを進めます。日本語で学べるのは大きいですね。

Auto Scalerなど一部の章はPCF独自機能ですが、ほとんどの内容はCF共通です。始めてCFを学習する方に最適なトレーニングです。

そして、このトレーニングに対応した資格試験があります。

https://pivotal.io/training/certification

対策としては、上記のサイトにあるExam Briefで各章のウェイトを確認し、Study Guideにまとまっているポイントを確認しながらトレーニングのテキストを復習するのが一番いいです。

トレーニングを受けていなくても資格だけ受験もできますので、PCFユーザーでなくても活用しやすい資格です。

問題はすべて4択で、出題はとてもストレートです。妙にひねった問題とかは出てきません。

Cloud Foundry Foundationはちょっと重たい、という場合はこちらを目標に学習されてもいいと思います。

公式ドキュメント

やはり、最後は公式ドキュメントを確認しましょう。ここに書いてある情報が一番正確なはずです。

Cloud Foundry Docs

最後に

Cloud Foundryに限らず、最近は日本語の技術情報が少なくなってきました。どうしても英語は読まざるを得ないですね。

また、ようやっとトレーニングも出来ましたので、ぜひ活用してください!

Java EEにMVCはなぜ必要なのか

$
0
0

この記事は?

Java EE Advent Calendar 2017の22日目です。

6日目の@khasunumaさんの記事「MVC のこれまでとこれから」で、MVCがこれまで辿ってきた経緯が解説されていました。

僕は個人的にMVCを待ち望んでいました。早い段階からブログを書いたり、JJUG CCCで発表したりもしていました。今でも、「MVC 1.0」でググると多くは僕の記事がヒットします。

蓮沼さんは上記の記事では、「MVCはあるに越したことはないが必須ではない」というご意見でしたが、僕はこの記事のタイトル通り「MVCは必要」という意見です。

世の中には色んな意見があっていいと思いますので、ここで論じてみたいと思います。少しでも参考になれば幸いです。

意見1: Java開発者の多くはアクションベースフレームワークに慣れている

JavaでWebアプリケーションを作る場合のフレームワークといえば、昔のものになりますが、やはりStruts 1.xやSeasar2(正確にはS2StrutsSAStruts)が多勢を占めるでしょう。これらはすべて、HTTPのリクエスト・レスポンスのやり取りを記述する「アクションベースフレームワーク」に分類されます。他のフレームワークも、ほとんどがアクションベースでしょう。

それに対して、JSFは「コンポーネントベースフレームワーク」です。画面のパーツやイベント(ボタン押下など)に着目して実装します。JSF以外にもコンポーネントベースフレームワークは存在しますが、Javaでは少数派です。また、Swing・JavaFXAndroidなどによるGUIプログラミングを経験したことがある人は、Webアプリをアクションベースで作った経験がある人に比べれば少数でしょう。

つまり、多くの人はアクションベースに慣れており、コンポーネントベースに慣れている人はあまり多くありません。(あくまで僕の実感ベースですが)このような状況下で、特に大人数の開発者が必要なプロジェクトでは、「よし、コンポーネントベースのJSFを採用しよう」とはならないのではないでしょうか。

もちろん、サーバーベンダーのサポートを受けたいからJava EE標準で作りたいという場合は、選択肢がJSFしかありませんので、JSFが採用されるでしょう。しかし、もしJava EE標準のアクションベースMVCも選択肢として存在するなら、JSFではなくMVCの方が採用されるのではないでしょうか。

意見2: すべてのWebアプリがフルJavaScriptで画面を作られる訳ではない

確かに、いまJavaScriptでUIを構築することが増えています。Angular・React・Vueなど、JavaScriptフレームワークの進化はとても速いです。もちろん、画面をすべてJavaScriptとピュアなHTMLで書くことも多いでしょう。

しかし、すべてのWebアプリがそうではないと思います。従来のように、サーバーサイドでHTMLを出力し、JavaScriptを補助的に使うようなアプリもまだまだ存在するでしょう。

JSFは、この用途には向いていません。画面上にJavaScriptで処理を記述すると、JSFが内部的に使っているJavaScriptコードと競合したり、画面上で処理した結果がサーバー側で保持しているコンポーネントツリーと矛盾したりして、うまく動かないことがあるからです。

なので、シンプルに「サーバーサイドでHTMLを出力するだけ」のフレームワークが求められます。それがMVCなのです。

これからMVCはどうなる?

蓮沼さんのブログにもある通り、今もMVCは仕様策定プロセスが進んでいます。現スペックリードの1人であるIvar GrmstadさんはEE4Jでも中心人物であり、今後はEE4Jの傘下で積極的な活動が続くでしょう。実際に、つい先日(12月18日)、Public Reviewという重要なバージョンがリリースされました!

www.mvc-spec.org

前のバージョンであるEarly Draft Review 2は2015年11月であり、2年以上ぶりのリリースになります。とても感慨深いです。

正式リリースがいつになるかは現時点では不明です。完全に僕の予想ですが、早くて2018年、遅くとも2019年前半には正式リリースになるのではないでしょうか。

MVCに限らず、Java EEはこれからどのように仕様策定プロセスをすすめるのかなど、EE4Jで検討中の事項が多いです。まだしばらく待つ必要がありますが、期待して待ちましょう。

JJUG CCC 2018 Springで登壇してきた

$
0
0

登壇してきた

今回も登壇の機会をいただきました。タイトルは「Pivotal認定講師が解説!ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説」です。スポンサーとしてのセッションでした。

その名の通り、Spring 5 & Boot 2のリアクティブ以外の新機能をまとめて解説しました。Core/Web/Data/Security/Test/Bootの6つに分けています。資料はSlideshareにアップしました。

アンケート結果は下記。ご満足いただけたようで良かったです。今回(というか今日?)から平均値とかが出るようになったんですね。

f:id:MasatoshiTada:20180529100439p:plain

f:id:MasatoshiTada:20180529100453p:plain

この発表の基になっているのは、公式のリファレンスやGitHub、去年参加したSpringOne Platformの各セッションなどです。けっこう取捨選択していますので、興味のある方はぜひ原典をあたってみてください。上記スライドの最後の方に、各資料へのリンクを貼ってあります。

これでCCC登壇は9回連続9回目になります。初めて出たのがもう4年前か・・・。早いなあ。もちろん、次回も頑張りたいです。

参加したセッション

Spring Boot Actuator 2.0 & Micrometer (槙さん)

僕の師匠である槙さんのセッション。内容としてはMicrometerが中心でした。理解があってるかどうかビミョーですが、メトリクス取得機能+各監視ツール(DataDogやPrometheusなど)に合わせてデータを整形する機能を持っているようです。

ちなみにこの朝イチの時間帯、個人的に聞きたいセッションが重なっていて選ぶのに困りました。できれば全部聞きたかった・・・。

Swagger(OpenAPI Specification)入門 (正野さん)

Swagger自体は知っていましたが、使ったことがなかったので聞いてみました。各Swagger Xxxの関係性が分かりやすくて良かったです。

ある程度前提知識があったので個人的には前半の内容が少し冗長に思えましたが、その分まったく初めてという方にもわかりやすいセッションだったと思います。

How to Properly Blame Things for Causing Latency: An Introduction to Distributed Tracing and Zipkin (Adrian Coleさん)

マイクロサービスで必要不可欠な分散トレーシング(ログを1箇所にあつめてほげほげするやつ)。そのデファクトであるZipkinのセッションです。発表者のAdrianさんはその作者です。元Twitterで今はPivotalに所属されているとか。

通訳ナシのセッションだったのですが、とても優しい口調でゆっくり喋っていただけたため何とか理解できたと思います。懇親会で質問したかったんだけど、自分のLTとかその他もろもろでできなかった・・・😭。次こそは。

Spring Cloud, Docker & Kubernetes - Lessons Learned in the context of an OSS Project (Daisuke Yoshimotoさん, Mauricio Salatinoさん)

連続で英語セッションでした。吉本さんは最初だけで、発表はほとんどMauricioさんでした。Adrianさんとは対象的にメチャ早口・・・😅。正直、あんまり理解できませんでした。内容としては、Kubernetesというよりマイクロサービス一般の内容が中心だったと理解しています(違うかもしれない)。

Spring Boot on Kubernetes : Yahoo!ズバトク事例 (玉利さん)

Yahooさんのシステムリプレイス?事例。Spring Boot + Kubernetesという構成。話の内容としてはKubernetesの基礎や、Kubernetes上でSpring Bootアプリを動かすためにやったことや注意点などで、とてもわかりやすかったです。

個人的には、Spring Data JPAJPA実装をEclipseLinkにし、その独自機能でDBシャーディングをしていた部分。Spring Data JPAでEclipseLinkを使った事例は初めて聞いたので、とても参考になりました。

DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話 (福嶋さん)

Java 100本ノックのジャストシステム福嶋さんのセッション。こないだの技術書典で初めてお話しできたので、セッションも聞いてみたいと思い参加しました。

DDDやクリーンアーキテクチャーについてはあんまりしらないのですが、マイクロサービスの流れでよく聞くキーワードです。ただ、今回の福嶋さんのセッションだと、DDDやクリーンアーキテクチャーが先にあって、その結果マイクロサービスになったという理解です。

この最後の時間帯も、聞きたいセッションがいくつも重なっていました。選ぶのが大変・・・!

懇親会

LT

個人で懇親会LTのCfPを出したら通りました。去年、海外カンファレンスに初参加したときに体調を崩して病院にいった話をしました。そこそこウケてよかったです。資料は技術系じゃないのでアップしてません。

風船

発表者は風船をつけて分かりやすいようにするという新たな試みがされていました。ただし諸事情で上に浮かばなかったので、腕にくくりつけるだけでしたが😅。。。しかし、やはりそれでも風船が目印になったのか、懇親会で「セッション聞いてました!」とお声がけいただける機会が以前よりも格段に増えたように感じました!次回はぜひ上に浮かぶようお願いします!ww

LINEさんのお寿司

以前もあって話題になったLINEさんのお寿司、再び登場!前のときはネタがマグロだけだったような気がするんですが、今回は赤貝・いくら・うに・エビなど盛りだくさん!いやー、これは本当にすごい・・・。LINEさん、ありがとうございます!

気になった点

運営が非常にスムーズで問題点らしい問題点は見つからなかったのですが、あえて言うならアンケートの回収率かなと・・・。運営の方が全セッションの冒頭や終了時に「アンケートにご協力お願いします!」とアナウンスしてくださっていますが、このブログ執筆時点で僕のセッションへの回答数は40ほどです。セッションに参加いただいた方の1割ちょっとくらいだと思います。

確かに、僕自身も含めて参加者としてはイチ早く次のセッションの座席を確保するために移動したいし、そうするとどうしても前のセッションのアンケートは忘れがちになりそうです(結局、僕は30分休みのときにまとめて書きました)。

具体的なアイデアは今のところ思いついていないのですが、どうにかなれば、と思います。

最後に

今回もめいっぱい楽しむことができました。JJUG幹事の皆さん・ボランティアスタッフの皆さんには頭が下がります。いつも本当にありがとうございます。

僕もスピーカーとしての貢献を続けていきます。

Thymeleaf 3のドキュメント和訳をお手伝いしてコントリビューターになりました!

$
0
0

@bufferingsさんとThymeleaf 3のドキュメントを和訳し、それが今日、公式サイトで公開されました!

Tutorial: Using Thymeleaf (ja)

もともとThymeleaf 2.xのころに@bufferingsさんが翻訳されていたものが既にあったので、僕がやったのはその差分のごく一部、ですが😅

コードで貢献した訳ではありませんが、正式にThymeleafのコントリビューターとなりました。

これまでもThymeleafやPayaraなど、OSSのバグをIssueとして報告したりはしていましたが、コントリビューターとなったのは初めてです。

Thymeleafをお使いの方のお役に立てれば嬉しいです。

研修の価値とかコミュニティのこととか思ったこと色々

$
0
0

いろふさんがブログを書いてくれたので触発されて書きます。

irof.hateblo.jp

今日、自社で担当した研修を、いろふさん(@irof)とかずひらさん(@kazuhira_r)がご受講くださいました。

自分より技術レベルが圧倒的に上な方々に対して何かをレクチャーするという非常に緊張するシチュエーションだったのですが、結果的にはご満足いただけたようで何よりです。

いろふさんのブログで印象的だったのは下記の部分。

内容は期待通り、断片的な知識がリンクされ、抜け漏れや曖昧なものが補強されていくのが実感できました。 これまでやってきたのも、そう間違ったものではなかったのはちょっと安心(これを確認するのはちょっと怖かった)。

いろふさんレベルの方でも不安があるんだ・・・というのが初めて読んだときの感想。

ただ、僕が研修を作るためにやっているのは、リファレンスを読むこと、ソースコードを読むこと、実際にアプリを作って実験してみることくらいです。

いろふさんや多くのエンジニアの方々と変わらないと思いますし、たぶんもっと高いレベルでそれをやっていらっしゃるはずです。

僕自身も、知識が偏ってるんじゃないか、エンジニアの方々と比べて知らないことが多いんじゃないか、と不安になることは多いです。

そこで思ったのは(ちょっと思考が飛びますが)、技術にしても何にしても絶対的な「正解」というものは無くて、誰かと「答え合わせ」しながらやってくしかないんじゃないか、ということ。

その答え合わせの場が研修であり、コミュニティではないのかなと。

答え合わせの相手として、いろふさんやかずひらさんが僕を選んでくれたのは本当に嬉しいし、今まで努力してきた甲斐があったなと思います。

あと最近思うのは、やらなきゃいけない技術の範囲が本当に広くなっていて、優れたエンジニアの方でも1人ですべてカバーするのはかなりキツイんじゃないかと。

そういった意味でも、世の中のエンジニアの皆様にもっとカジュアルに研修を使ってほしいな、と思いました。

あ、そういえば。僕も今日答え合わせできました。

お客様に増田さんの本をおすすめしたのは間違いじゃなかった。

まとまってないけど、以上!

Viewing all 88 articles
Browse latest View live