Tuesday, May 6, 2014

spring-bootと組み込みTomcatが便利すぎて鼻血でそう

Tomcat embeded - 組み込み型Tomcat - が正式にサポートされたのは2011年5月のTomcat7.0.14の前後あたりのようです。もう3年も前です。 一方で2014年4月、Spring frameworkはSpring Boot 1.0.0を正式にリリースしました。

この二つのニュースを別個に見ると「ふーん」としか思えません。時間軸もズレすぎですし。 しかし、最近、某所でSpring-Bootとtomcat-embededを組み合わせて使ってみたら、便利すぎて鼻血出そうになりました。

便利さがうまく伝わるかどうかわかりませんが、せめてメンテついでにMixer2のサンプルアプリで使ってみるか、と思いまして、 mixer2-fruitshop-springbootを作りました。 動かし方はこちらのページとほぼ同じ。

SpringFrameworkと組み込み型Servletコンテナをうまいこと組み合わせてくれる、という機能はspring-bootの数多くの機能のうちのひとつにすぎませんが、 とにかくここでは組み込みTomcatとの連携機能の話だけにします。

とりあえずmixer2-fruitshop-springbootをざっくりご覧いただきつつ ポイントを挙げます。

  • src/main/webapp/WEB-INF/web.xml のようなフォルダやxml設定ファイルはもはや存在しません。こうした旧来型のWebアプリケーションとしての構造は分業開発の妨げになりやすいのですが、これは普通の単純なjavaライブラリとまったく同じ構造です。もちろんこれは、Servlet3.0準拠であることや、あるいは、ビューエンジンとしてjspではなくMixer2を使っているおかげでビューのテンプレートをwebappとかWEB-INFとかそういうところに置く必要が無い、ということによる効果でもあります。
  • pom.xmlのbuildタグ周辺を見てください。実質的にはmaven-jar-pluginとmaven-dependency-pluginが使われているだけです。特別なビルド方式は必要ありません。spring-bootにはmaven用のプラグインもあれこれ用意されているのですが、ビルド方式までもが特定のフレームワーク提供のプラグインに縛られるのは個人的には好みではないのでこの方法を採用しました。これにあとmaven-assembly-pluginを追加して、アプリ本体のjarとlibフォルダ配下に集められるjarをまとめてzip化するようなセッティングをすれば、リリース成果物の生成も簡単です。
  • pom.xmlのpackaging指定はwarではなくjarです。このwebアプリケーションはmvn packageするとjarファイルになります。いわゆるfat-jarではなく純粋なjarです。tomcat-embeded-x.y.z.jar等の組み込みtomcatライブラリの助けを得ながらwebアプリケーションとして起動します。コマンドラインで言えば java -jar mixer2-fruitshop-springboot-1.0-SNAPSHOT.jar -classpath "lib/*" で起動できます。
  • サンプルアプリではServerクラスにmain()メソッドを置いてあります。eclipse等での開発作業中はこのserverクラスを通常のjavaアプリとして起動し、ブラウザで8080ポートを見て動作確認をします。繰り返しますがwebアプリではあるものの構造上は単なるjavaアプリなので、eclipseでWTPのようなプラグインは必要ありません。tomcatも別途用意する必要がありません。だって組み込みtomcatだから。ただのjavaアプリだから。
  • tomcatのcontext.xmlやwebアプリとしてのWEB-INF/web.xmlにあたるものは全てjavaコードとして記述します。サンプルアプリではMvcConfigurationやSessionTrackingConfigListenerにあたります。もちろんここのコード上で設定されている値はspringの種々の機能を使えば、他の設定ファイルやコマンドライン引数等で外側から上書きすることが可能となります。Springのprofile機能も使いこなせるでしょう。

こんな話だけでは便利さが伝わらないかもしれません。とにかくこれはちょっとしたパラダイムシフトですね。 これからは、「tomcatを用意してそこにSpringMVCによるwebアプリケーション(*.warファイル)をdeployする」のではなくて、 「webアプリケーションとtomcatをSpringFramework上で起動する」という感覚になります。もう、webアプリとtomcatを別々に用意する必要はないのです。これらは、ひとつです。

Sunday, April 6, 2014

第5回 #渋谷java でトークしてきた

今日はこんなイベントに参加してきました。

第五.五回 #渋谷java - connpass

javaに関することなら何でもありのゆるふわjava LTイベントです。

参加される方はSIerの方や自社プロダクト開発の方やフリーランスの方など様々です。 LTの内容は初心者向け〜ガチ勢向けまで幅広く実施して頂いておりますので初心者の方もモヒカンの方お気軽にどうぞ!

2月にやるはずだったのが大雪のため4月に延期になったやつです。 私はセッション枠で20分ほどしゃべらせていただきました。資料がこちら。

その場でJenkinsを「ポチっとな」してMixer2のビルドとセントラルリポジトリへのデプロイ作業を生実演でお見せするという試みがけっこうウケたようで、うれしかったです。 ついでなのでプレゼンで語りきれなかったことを少し書きます。

perlならcpan, PHPならPEARやPECL, rubyならrubygems そしてJavaならmavenセントラルリポジトリのように、近代的なプログラミング言語のほとんどが、 パッケージリポジトリ=コンパイル済みで即利用可能な状態のライブラリの集積所=と、それをうまく使いこなすためのコマンド機構を持っています。

mavenはビルドツールではありますが、そのキモはmavenセントラルリポジトリとの自動的な連携にあります。これはGradleでもAnt+Ivyでも同じことが言えます。 java以外の言語でも似たようなものです。 だからこそ、現代のプログラマーはパッケージリポジトリのことをもっと意識しそこに貢献すべきです。今日のトークの動機はそこにあります。 ソーシャルコーディングに必要なのはGitHubだけではないのです。

mavenセントラルリポジトリにライブラリをupする権限を得るには審査が必要だという話をしましたが、 それはあくまで形式的なものです。 たとえばgroupIdが他とバッテイングしてないかとか、pomの書き方ちゃんとわかっていそうかとか、 MITかGPLかApache2かライセンスをちゃんと表示しているかとか、 なにかの商標にひっかかってなさそうかとか。。。 逆に言うと「おまえの作ったjavaライブラリはmavenセントラルに入れてもいいほどすっげえ便利かどうか」ということは考慮されません。 それはsonatype.orgの中の人が決めることではなく、全世界のjavaユーザーが決めることだからです。

門戸は開かれています。さあ、あなたもこれで、javaのOSSライブラリ開発者!

なお、他の方のトークで個人的に面白かったのがこちら。

@テスト
public void 文字列マッチャーのテスト() {
    文字列("テストなんとか", は("テスト".で始まる()));
}

っておいなんだこれw

最後になりましたが、運営の@seri_kさんほか会場設営などやってくださっているビズリーチ社の関係者の方々に感謝します。私も結構ガチで転職を考えております。w

参考リンク: 第五.五回 #渋谷java - Togetterまとめ

Tuesday, January 28, 2014

Mixer2でページのヘッダとフッタを挿入する方法

「Mixer2でビューを作るとき、いろんなページで共通のヘッダやフッタ部分を挿入するのってどうやるのだろう?」 よくあるケースです。JSPで言えば <jsp:include page="header.jsp"> にしておきつつ、 header.jspファイル内には <div id="header">ヘッダーのなか</div> のように書いておくやつ。

しかし、JSP的なやり方だと、ヘッダはヘッダ、フッタはフッタ、のようにバラバラになってしまい、 webデザイナーの立場からするとメンテが面倒なうえに実際の見栄えの確認がしづらくなってしまいます。 Mixer2ではいろいろなやり方がありますが、わかりやすくかつ手っ取り早いのが、パーツ取り用htmlテンプレート作戦です。

まず、通常の画面表示用テンプレートの他に、 parts.html のような名前でパーツ取り専用テンプレートを用意し、そこにヘッダとフッタのブロックを自由に書きます。

 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
    <meta charset="utf-8" />
 </head>
 <body>
 <div id="header">
  実際にヘッダにしたい内容
 </div>
 これはパーツ取り専用htmlなので実際には出力しませんよ
 <div id="footer">
  フッタにしたい内容
 </div>
 </body>
 </html>

次に実際に画面に出すテンプレートファイル(fooTemplate.htmlだとします)には次のように書いておきます。

 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
    <meta charset="utf-8" />
 </head>
 <body>
 <div id="header">
  ここにヘッダがはいる予定です
 </div>
  実際に出力したいコンテンツ...
 <div id="footer">
  ここにフッターがはいる予定
 </div>
 </body>
 </html>

画面出力のviewクラスはこんな感じ。(あくまでも模式的な例です)

Html partsHtml = mixer2Engine.loadHtmlTemplate("parts.html");
Div headerDiv = partsHtml.getById("header",Div.class).copy(Div.class);
Div footerDiv = partsHtml.getById("footer",Div.class).copy(Div.class);
Html fooHtml = mixer2Engine.loadHtmlTemplate("fooTemplate.html");
fooHtml.getBody().replaceById("header", headerDiv);
fooHtml.getBody().replaceById("footer", footerDiv);

実際には、テンプレートのロードを何度もやるのはやや非効率です。 共通クラスを切り出して、そこでparts.htmlのロードを一回だけ行ってheader/footer用Divインスタンスの copy()の結果を返させて、それを使うような感じがよいでしょう。

「fooTemplate.html上に <div id="header">ここにヘッダが入る</div> みたいなことを書く手間すら省きたい」という要求も実現可能です。

Html partsHtml = mixer2Engine.loadHtmlTemplate("parts.html");
Div headerDiv = partsHtml.getById("header",Div.class).copy(Div.class);
Div footerDiv = partsHtml.getById("footer",Div.class).copy(Div.class);
Html fooHtml = mixer2Engine.loadHtmlTemplate("fooTemplate.html");
// bodyタグの先頭にヘッダdivを差し込む
fooHtml.getBody().getContent().add(0, headerDiv);
// bodyタグの最後にフッタ用divを差し込む
fooHtml.getBody().getContent().add(footerDiv);

こんな感じ。

いかがでしょう。Mixer2でのビュー実装の書き方は様々です。 jspのカスタムタグではなく通常のjavaで書くので柔軟性とテストの書きやすさは段違い、というのがポイントです。 要件に合わせてご自由にどうぞ。

Thursday, January 9, 2014

Java5で動くMixer2をリリースしました(あくまで実験的)

Java5がリリースされたのは2004年10月。そして今はもう2014年です。もうすぐJava8も出ます。 そんな時期にMixer2をjava5でも動かせるようにするってそれ誰得?ww というツッコミもけっこうありました。(※Mixer2は本来はJava6以上が動作条件です)

しかし、世の中にはレガシーなシステムなんていくらでもあるようです。詳しくは言えませんが、 Java1.4(5ですらない!)で現役で稼働しているシステムが存在し今もチビチビ改修していると言う話を、つい先日まのあたりにしました。 Javaから離れてしまいますが、全日空の国内線旅客システムが実はつい最近まで Fortran(COBOLですらない!)で動いていたというニュースもありましたね。

さて、話をMixer2に戻しましょう。 Mixer2はJavaのJAXB-APIを使ってXHTMLを入出力しています。JAXBはJava6以降でJDK/JREに標準搭載となったため、 本来、Java5では動きません。

ただ、jaxbはもともと独立したライブラリとしてSunの社内で開発が続き、のちにJava6で初めて実行環境に標準搭載されたという経緯があります。 これはjaxbに限ったことではなく他のapiでも似たような流れをたどることがあります。

ということは、jaxbやその関連の、既に公開されているライブラリを、 Mixer2が依存ライブラリとして使用するようにすればJava5でも動くということになります。 そう、実はそれほど遠い道のりではないのです。実際1日2日でできちゃったし。

そんなこんなでとにかく、mixer2-java5 version 0.1.2 をリリースしました。

使い方は本家Mixer2とまったく変わりありません。ただし、以下の点にご注意ください。

  • あくまで実験的なものですので、サポートやバージョンアップはそれほど期待しないでください。
  • SpringMVC関連機能は削り落としてあります。純粋にテンプレートエンジン機能のみです。

Saturday, December 28, 2013

Mixer2の最近のリリースでのエンハンス(特にSpringMVC関連)

Mixer2-1.2.22をリリースしました。

実はここ数週間で何回かリリースしましたが、まともにアナウンスしていませんでした。最近のリリースではどこをどういじったか、ざっくりまとめておきます。

1. Spring MVCとの組み合わせ方をドキュメントに書きました

Mixer2とSpringMVCと組み合わせたサンプルアプリケーションはもともとあったのですが、 javadocはともかく、文章の形では基本的な説明をまとめて書いてはいなかったので、 Use Mixer2 with Spring MVCというページを公式サイトにつくりました。 なお、もともとほぼ同じことがjavadocにも書いてありましたが、それも少し手直ししました。

※誤解の無いように念のため書いておきますが、Mixer2それ自体は他のライブラリ等への依存性が非常に少ない、独立性の高いxhtmlテンプレートエンジンです。 Webアプリケーションフレームワークと組み合わせて使うのが便利なことは確かですが、 必ずSpringMVCやSAStrutsと組み合わせないと何もできないということは全くありません。

2. Spring MVCでMixer2もJSPも両方使いたくてもうまく動かないのを直しました

公式サイトの説明のように


    
        
        
        
        
        
    
    
        
        
        
    

と書けば、コントローラから返されたview名を使ってMixer2ViewResolverがhtmlテンプレートファイルを見つけられなかった場合には、 そのままInternalResourceViewResolverへ処理が移って、view名に該当するjspが使われる...はずだったのですが、 実際にはMixer2VeiwResolverがhtmlテンプレートを見つけられなかった段階でいきなりFileNotFoundExceptionになってしまっていました。

それではまずいので、ちゃんと次のリゾルバーに処理が移るように直しました。このへんは、SpringMVCのマニュアルにも書かれている通りにしてみた、という感じです。

17.5.2 Chaining ViewResolvers

"The contract of a view resolver specifies that a view resolver can return null to indicate the view could not be found. Not all view resolvers do this ..." (ビューリゾルバーの実装ルールとしては、ビューを見つけられない場合にはnullを返すことができますよ。ただ全部のビューリゾルバーがそうしてるわけじゃなくケースバイケース...)
Spring MVC reference 3.2.xより

ただし、従来の挙動(見つからなければ即座にFileNotFoundException)でよいという人のために、 この機能をオフにする設定方法も用意しておきました。細かいことはMixer2XhtmlViewResolverのjavadocに書いてあります。

3. headタグの中ではremoveById()等が動かないことがあるのを直しました

単純にバグです。

4. 恥ずかしいミススペルを直しました

PathAjusterクラスはクラス名自体の綴りが間違っていることが今頃発覚w。 機能はそのままでPathAdjusterクラスとして作り直しました。 古い方のクラスは@Deprecatedにしておきましたが、こういうので後方互換性を失うのはまずいのでたぶんずっと消さずに残しておくと思います。

5. HTML5でAタグの中のDIVタグ等が消えるのを直しました

Mixer2-jaメーリングリストのほうでもらったバグ報告の対応です。

htmlテンプレートとしてmixer2Engineがロードするとき、テンプレート上のaタグの中にインライン要素(spanとかimgとか)が入ってるのはokだが、 ブロック要素(divとかpとか)が入っているとそれが消えてしまうという現象です。

これはちょっと盲点でした。というのは、html4.xまでの規格では、aタグの中にブロック要素を入れるのはNGなのです。 Mixer2はJAXBを使ってhtml(xhtml)を読み込むので、そういったところも厳格にNG扱いで、該当要素を無かったことにします。 ところが、html5ではaタグの中にブロック要素も入れられるようになりました。 HTML5 の “ブロック・レベル“ リンクというやつです。 Mixer2のhtml5に対する対応の不足、というバグとして対応しました。

ここ数週間のMixer2のエンハンス、ざっくり解説してみました。安心して最新版をご利用ください。今後ともごひいきに!

Monday, December 23, 2013

JAX-RSのビューとしてMixer2を使ってみる

こんにちは。nabedgeこと渡辺です。 ひとつ前の記事はJava Advent Calendar2013のやつでしたが、 今日はJava EE Advent Calendar 2013の23日目なんです。 JavaじゃなくてJavaEEです。ここでSpringMVCがどうのとか言っちゃうといろんな人が(コンコン、おや誰かきたようだ

そんなわけで、JavaEE規格の中でもWeb系エンジニアにとって最も身近な、JAX-RSのお話です。

今年の3月頃、 JAX-RSはHTML Webアプリケーションを開発するのに充分なフレームワークであるか? - AOEの日記 というエントリが結構話題になりまして、そこではこんな話もありました。

テンプレート処理パートの実装について

(中略)
ただ、普通のJSPプログラミングであるため、エラー時にメッセージやハイライトをしたり、条件に応じた表示変更と言った処理もゴリゴリ実装する必要があります。これが地味にめんどかったりします。少し大きな規模の開発案件になった場合はある程度プレゼンテーションレイヤで必要となるライブラリを整備してあげる必要があると思います。

そのとおりです。javaのmvcフレームワークは、案外どれも「ビューはjsp(jsf)で」と一言書いてあるだけです。 しかし現実世界に置けるM,V,CのViewは、それほど単純ではありません。むしろ、ビューは十分に複雑です。

JAX-RSの設計思想として、httpレスポンスをhtmlではなくjsonやxmlで返すことに主眼を置いているように思えます。 素直に考えると、クライアントサイドはJavaScript等で実装しサーバーから受け取ったjsonやxmlを料理せよ、ということでしょうし、 実際そうしようとしている開発現場も増えてきているかもしれません。 しかしそのためにはBackbone.jsやAngular.jsといったクライアントサイドMVCフレームワークの使い方も覚えなければなりません。 Webデザイナーの仕事とうまく歩調を合わせることまで考えると、道のりは険しそうです。

話をサーバーサイドに戻しましょう。 Viewを実装するために、jsp、jsfあるいはVelocityやThymeleafのようなテンプレートエンジンの特殊文法を覚えたり、 それでも足りなくてカスタムタグやプラグインを書き、気がつけばWebデザイナーさんの仕事は置いてけぼりになっている。 そんなことになるくらいなら、はじめからViewをjavaで普通に書けばいいじゃない! テンプレートは普通のhtml/cssで!それがMixer2の存在理由です。

前置きが長くなりましたがとにかく、html主体のwebアプリケーションを、JAX-RSとMixer2で作る、簡単なサンプルを作ってみました。 ソースは https://github.com/nabedge/mixer2-sample/tree/master/mixer2-jaxrs-sample です。

jax-rs実装にはjersey、サーバはtomcatを想定しています。(あっ、なんでglassfishじゃねーんだって言われそう^^;)

ポイントは二つ。まず一つ目が、リソースクラスのメソッドの戻り値がorg.mixer2.jaxb.xhtml.Html型であることです。 IntexResource.javaをご覧ください。

    @GET
    @Produces(MediaType.TEXT_HTML)
    public Html index(@QueryParam(value = "message") String message)
            throws IOException, TagTypeUnmatchException {

        // loading template
        String template = "m2mockup/m2template/index.html";
        InputStream is = this.getClass().getClassLoader()
                .getResourceAsStream(template);
        Html html = mixer2Engine.loadHtmlTemplate(is);
        
        // replace content in <div id="message"> tag
        if (message != null) {
            Div div = html.getBody().getById("message", Div.class);
            div.unsetContent();
            div.getContent().add(message);
        }
        
        // replace static file path
        Pattern pattern = Pattern.compile("^\\.+/.*m2static/(.*)$");
        PathAjuster.replacePath(html, pattern, "m2static/$1");
        
        // return html object
        return html;
    }

Html型を返されたjerseyは、それを処理しうるMessageBodyWriterを探して引き継いでくれます。 それがMixer2Writer.java です。

@Provider
@Produces(MediaType.TEXT_HTML)
public class Mixer2Writer implements MessageBodyWriter {

    // -- snip --

    @Override
    public void writeTo(Html html, Class type, Type genericType, Annotation[] annotations,
            MediaType mediaType, MultivaluedMap multivaluedMap,
            OutputStream outputStream) throws IOException, WebApplicationException {
        // marshalling html object to string.
        String str = mixer2Engine.saveToString(html);
        OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8");
        writer.write(str);
        writer.flush();
    }
}

Html型のインスタンスをMixer2Engineに渡して文字列化し、そのまま出力しているだけです。

いろいろ急いでしまったので、突っ込みどころだらけです。リソースクラス内でビューの処理もやってしまっている点はイケてなくて、 本来ならViewable やViewableContext をうまく実装して切り分けるべきでしょう。そもそもJavaEEだっつってんのになんでGlassFishじゃなくtomcatで試しているんだとか。 Mixer2Engineの呼び出しもCDIを使うほうがJavaEEらしくなるでしょう。

このサンプル、どなたか試していただいて、もちょっとカッコよくしていただけませんか? マサカリも歓迎ですが、Pull Requestはもっと歓迎です。だってほら、クリスマスだし。

Sunday, December 8, 2013

Mixer2のSpringMVC連携機能がver 1.2.17でさらに進化!

こんばんは。nabedgeこと渡辺です。 この記事はJava Advent Calendar 2013の8日目です。

さて、私が作っているMixer2というテンプレートエンジンですが、 秋口に秀逸な pull request をいただいたので、ありがたくマージしてversion1.2.17をリリースしました。

本当は先週リリースした1.2.14で既にマージ済みだったのですが、 JavaDocに書いたサンプルコードのとおりに書くと動かない(笑)というヤバいのがあったのでリリースしなおしました。 そのJavaDocを書いたのはプルリクをくれた人ではなく私です。 さらに言うと、リリース作業で凡ミスして1.2.15と1.2.16を欠番にしてしまったのも私です。 ^^;)

そんなことはさておき、何が新しくなったのかというとSpringMVCとMixer2を連携させるためのViewとViewResolverです。 とりあえずフルーツショップサンプルアプリケーションの商品配送先住所の入力画面用のコントローラで説明してみます。

@RequestMapping(value = "/shipping")
public String shipping(Model model,
    @RequestParam(value = "redirected", required = false) boolean redirected,
    @Valid Shipping shipping, Errors errors) {

    model.addAttribute("shipping", shipping);
    model.addAttribute("redirected", redirected);
    model.addAttribute("errors", errors);
    return "checkout/shipping";
    // 以前のMixer2ではここで return "shippingView" のように、
    // springコンテナ上にDI済みのviewクラスの名称を
    // 与える必要があったが、新しいMixer2では
    // テンプレートファイルのパスでよい。
    // そしてテンプレートファイルのパスは
    // Viewクラスのパッケージ名/クラス名とそのまま紐づくルール。
}

コントローラの戻り値はテンプレートファイルのパスそのものです。 つまり戻り値の書き方はInternalResourceViewResolver + JSPを使う場合と同じでいいところがポイントです。

次に、配送先住所の入力画面のViewクラスを見てみましょう。

// Viewクラスに@ComponentのようなDIアノテーションは不要。
// 新しいViewResolverが代わりにやってくれる。
public class ItemView extends AbstractMixer2XhtmlView {

    @Autowired
    protected FooBar fooBar; 
    // もちろんSpringコンテナから任意の
    // オブジェクトをDIで受け取れる

    @Override
    protected Html renderHtml(Html html, 
            Map<String, Object> model, 
            HttpServletRequest request,
            HttpServletResponse response) 
            throws TagTypeUnmatchException {

        // Html html = mixer2Engine.loadHtmlTemplate(filePath);
        // のようなコードは不要。
        // 新しくなったAbstractMixer2XhtmlViewが、
        // コントローラのメソッドの戻り値で指定された
        // パスを使ってあらかじめテンプレートをロードして
        // Htmlオブジェクトに格納済み。

        @SuppressWarnings("unchecked")
        List<Category> categoryList = (List<Category>) model.get("categoryList");
        Item item = (Item) model.get("item");

        // embed item box
        replaceItemBox(html, item);

        // 途中は省略

        return html;
    }

ここでSpringの設定のほうを見てみます。



    
    
    
    
    

Mixer2XhtmlViewResolverのprefix,suffix,basePackageのプロパティがポイントです。 つまり、コントローラのメソッドの戻り値が "foo" の場合、
org.mixer2.sample.web.view.FooView がビュークラスで、
クラスパス上の m2mockup/m2template/foo.html がテンプレートファイルです。

コントローラのメソッドの戻り値が "foo/bar" の場合、
org.mixer2.sample.web.view.foo.BarView がビュークラスで、
m2mockup/m2template/foo/bar.html がテンプレートファイルということになります。

もちろんビュークラスはAbstractMixer2XhtmlViewを継承していなければなりません。 なお、複数のテンプレートを組み合わせてhtmlを生成したい場合は、ビュークラス内で getMixer2Engine()でいつでもエンジンを使えますので、好きなテンプレートをいくらでもロード可能です。

クレバーなプルリクをくださったkazuki43zooさんに感謝!

Java Advent Calendar 2013、 次はJavaFXの大御所、skrbさんです。

Wednesday, November 27, 2013

メールアドレスとRFCの話

確かに定期的に繰り返される話題ですね。

「メールアドレスのルール」なんて使ってはいけない3つの理由

問題点1. メールアドレスに関して、RFCなんてそもそも守られていない

2009年以前に登録されたDoCoMo携帯のメールアドレスなど、quoted-stringじゃないのにピリオド連続するものが実在している以上、彼らを許容するべきです。

今そこにある実装 >> (越えられない壁) >> RFC です。

※2009年以前に登録されたDoCoMo携帯のメールアドレスっていうのはつまり、 foo....bar@docomo.ne.jp みたいにドットが連続してたりするアドレス(RFC的にはNG)のことを指します。

んで、「今そこにある実装」を重視すべきなのであれば、以下も重視したうえで、 「やはり彼らを許容すべきではない」という結論も得られてしまいます。

ケースバイケースでしょう。

合わせて読みたい:Internet Explorer はIE特化アプリから一時的に日本を救ってくれたけど次回はもう助けてくれないよという 警告

Sunday, November 24, 2013

DevLove現場甲子園でしゃべってきました

もう先々週のことなんですが、DevLOVE現場甲子園2013というイベントでしゃべってきました。

webデザイナとエンジニアのチームワークを加速させるテンプレートエンジンmixer2 devlove現場甲子園

Mixer2ネタであることはともかく、プレゼン資料自体の使い回し感は否めません。すいませんすいませんすいません。

ほかの方もプレゼンもなかなか面白かったです。 webデザイナーの秋葉さんのプレゼンとか→ 「【DevLOVE甲子園2013】UIと画面遷移を設計するときに 破綻しないようにするための、 ひと手間」

あと、「バラバラの同僚を社内勉強会でつなげよう」っていうやつもなかなか。

最後になりましたが、devloveスタッフの方、本当にご苦労様でした。ありがとうございました。

Saturday, October 26, 2013

log4j2にログを集める

log4j, slf4j, logback, commons-logging... こんがらがりませんか?僕はこんがらがりました。

ある実験的なWebアプリの開発の過程では、ログを最終的に何に集約するか?logbackか?それとも...?と、迷い、 結局log4j2に集約しました。これはそのメモみたいなものです。

なお、「slf4j+logbackのほうがナウでヤングだろ」といったご意見はスルーです。好みとかポリシーの問題です。 また、いにしえより伝わるlog4j1.xではなく、log4j2.xっていうところもポイントです。 java.util.logging?えーっ?!却下。

1. 前提とか方針とか

  • 新規のJava-Webアプリを開発する。そのコード上で使うLoggerにはlog4j2を使う。
  • ベースはSpringMVCフレームワーク。spring自身は内部でcommons-loggingを使っているので、それもlog4j2に集められるように設定する。
  • Spring以外にもいろいろOSSライブラリを使うが、それが吐くログもできる限りlog4j2に集める。例えば、内部でslf4j-apiを使ってるOSSが最近はとても多い。
  • 設定はlog4j2.xmlに集める。とりあえずWebアプリ内部に同梱する。
  • ビルドツールはmavenを使う

2. mavenのpom.xml

dependenciesタグ内で先に書いてあるほうが優先されるので、ログ出力ライブラリは上のほうに書いておくのが無難です。log4j-coreがもちろんlog4j2の本体。 log4j-jclがcommons-loggingによる出力をlog4j2に中継させるやつ。log4j-slf4j-implはslf4jによる出力を(以下略)

    
        
            org.apache.logging.log4j
            log4j-core
            2.0-beta8
        
        
            org.apache.logging.log4j
            log4j-jcl
            2.0-beta8
        
        
            org.apache.logging.log4j
            log4j-slf4j-impl
            2.0-beta8
        

        ... other dependency...
    

maven使いじゃない人のために、これで実際どんなjarがビルドパスに入ってくれるのか、書いておきます。こんだけ。

log4j-core-2.0-beta8.jar
log4j-api-2.0-beta8.jar
log4j-jcl-2.0-beta8.jar
commons-logging-1.1.1.jar
log4j-slf4j-impl-2.0-beta8.jar
slf4j-api-1.7.5.jar
slf4j-ext-1.7.5.jar
cal10n-api-0.7.4.jar

3. log4j2.xml

log4j2.xmlをsrc/main/resourcesに置く。root(要するにデフォルト値)を設定するほか、 ログ出力を制御したいクラス名、パッケージ名に対して出力レベルや出力先(appender)を設定します。

4. コードを書く

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Foo {
    private static Logger logger = LogManager.getLogger();
    public void bar(String a, String b) {
        logger.debug("a={},b={}", a, b);
    }
}

ログに変数をいれたいときに、logger.debug("a=" + a + ",b=" + b ) などとやってしまいがちですが、 実はこれ、ログ出力メソッドよりも先に+演算子による文字列連結の方が先に実行されますので、性能影響が出ます。 logger.debug()なんて本番環境ではオフにすると思いますが、それでも文字列連結は無駄に実行されてしまうのです。 どの程度の性能差が出るかは Performance - Apache Log4j 2 に詳しく解説されています。 せっかくlog4j2を使うのですから、{}記号によるプレースホルダ機能を使うようにしましょう。

また、log4j1.xのときは、
provate static Logger logger = Logger.getLogger(Foo.class);
のように、ロガー名として自クラスを明示的に与えてloggerを作る必要がありましたが、 log4j2のLogManagerでは省略できます。 log4j2のほうが好みな理由はこれが地味に便利だからかも。