« 2015年9月 | トップページ

2015年10月の4件の投稿

2015/10/24

GWT2.5.1 on Super Dev Mode を今さらながら



GWT2.5はDevModeからSuperDevModeへの過渡期のもの(当時SuperDevModeはまだdraft的な扱いだったはず)なので、起動方法がちょっとこなれていません。
起動できるようになるまでにつまづきまくってしまったので、手順を記録しておきます (なお、聞くところによると2.6でもまた別のひっかかりポイントがあるとかないとか…)。

使用するソースコードはこちらです:
github.com/yukihane/hello-mvp4g/ (tag: tag/blog/20151024/super-dev-mode)
(別の用途で使用するために作成したリポジトリなので、名前は気にしないでください…)

初期コードのgreetingメソッド引数をString型から別のSerializableな独自型に変更したものになります。
ローカルに展開したらmainディレクトリに移動してください。

以下の手順で実行すればSuper Dev Modeで操作できるように成ります。
  1. (前述の通り)カレントディレクトリをmainに移します
  2. 次のコマンドを実行し、コードサーバを起動します。
    mvn clean process-classes gwt:run-codeserver
  3. コードサーバが起動したら、指示される通りブラウザで http://localhost:9876/ を開きます。
  4. これまた指示される通り、2つのブックマークレットをブックマークバーに登録しておきます。
  5. モジュール名(今回はMainModule)のリンクが表示されますのでそのページヘ飛びます。
  6. .gwt.rpcという拡張子のファイルリンクがあると思いますので、リンク先を保存します。今回は1ファイルのみです。
  7. 保存したファイルを target/main-0.0.1-SNAPSHOT/MainModule/ へ移動させます。
  8. 次のコマンドを実行し、webサーバーを起動します。
    mvn gwt:run
  9. アラートダイアログでコンパイルを促されると思いますので、先ほど登録したブックマークレット"Dev Mode On"を押しコンパイルを実行します。
これで正しく動作すると思います。コードを修正したら"Dev Mode On"を押して都度インクリメンタルコンパイルを行う必要があるのがDevModeと異なるところですね。

少し補足をしておきます。
コードサーバ起動前に明示的にmvn process-classesを実行しなければならないのはver.2.5特有のバグだそうで、2.6(or 2.6.1?)で修正されたそうです。
[INFO]       [ERROR] Errors in 'file:/home/yuki/programs/hello-mvp4g/main/src/main/java/com/github/yukihane/hello_mvp4g/client/MainModule.java'
[INFO]          [ERROR] Line 37: No source code is available for type com.github.yukihane.hello_mvp4g.client.GreetingServiceAsync; did you forget to inherit a required module?
[INFO]          [ERROR] Line 39: No source code is available for type com.github.yukihane.hello_mvp4g.client.Messages; did you forget to inherit a required module?
[INFO]       [ERROR] Unable to find type 'com.github.yukihane.hello_mvp4g.client.MainModule'
[INFO]          [ERROR] Hint: Previous compiler errors may have made this type unavailable
[INFO]          [ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
[INFO] [ERROR] Compiler returned false
また、gwt.rpcファイルを自身でダウンロードしdeploy無ければならないのも、後続のバージョンでは不要になっているらしいですので2.5特有の手順ということになります。
これを行わない場合、次のような例外が発生(Jettyのログに出力されます)し、GWT-RPCが行えません。
00:00:56.715 [WARN] greetServlet: An IncompatibleRemoteServiceException was thrown while processing this call.
com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException: Type 'com.github.yukihane.hello_mvp4g.shared.Information' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' and did not have a custom field serializer. For security purposes, this type will not be deserialized.
    at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:323)
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:206)
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:324)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
Caused by: com.google.gwt.user.client.rpc.SerializationException: Type 'com.github.yukihane.hello_mvp4g.shared.Information' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' and did not have a custom field serializer. For security purposes, this type will not be deserialized.
    at com.google.gwt.user.server.rpc.impl.LegacySerializationPolicy.validateDeserialize(LegacySerializationPolicy.java:127)
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserialize(ServerSerializationStreamReader.java:651)
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.readObject(ServerSerializationStreamReader.java:567)
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader$ValueReader$8.readValue(ServerSerializationStreamReader.java:140)
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserializeValue(ServerSerializationStreamReader.java:425)
    at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:312)
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:206)
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:324)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)


参考:

2015/10/12

Eclipseのちょっと賢いスニペットプラグイン Code Recommenders

Ctrl+Alt+Spaceを押すと良い具合にコードを挿入してくれるEclipseプラグイン Code RecommendersSnipmatch機能 について説明します。(※本プラグインは他にも機能があるので、スニペットプラグインというと語弊がありますが、今回はそこしか使わないのでご了承を…)
前エントリからの流れ上、SLF4Jロガーコードを挿入する例になります。

05completion


  1. Help > Eclipse Marketplace... メニューからCode Recommendersをインストールします。Eclipseのエディションによっては最初からインストールされている場合も有ります。また、"Installed"となっていても、Snipmatchは入っていない場合もあるようですので、Installed > Change ボタンを押して Code Recommenders Snipmatch が本当にインストールされているか見てみてください。
    01marketplace
  2. Window > Show View > Other... メニューからSnippetsを選択します。2種類あると思いますが、"Code Recommenders"の方を選択してください。
    02view_select
  3. "logger"でフィルタをかけるとLOG4JとSLF4Jのスニペットがヒットします。今回はSLF4Jを使いますので"SLF4J Logger" をダブルクリックしエディタを開いてください。
    (ちなみにこのエディタ、ちょっとバギーな感じです…)
    03snippetview
  4. Dependenciesに設定されているorg.slf4j.api:org.slf4j.apiをRemoveし、保存します。
    04dependencies
あとは、.javaファイル中のフィールド宣言箇所でCtrl+Alt+Spaceを押し、"log"などの単語を入力すると候補が表示されるので選択すれば挿入されます。

上記手順中、Dependenciesの項目を削除しましたが、Mavenプロジェクトだとorg.slf4j:slf4j-apiと指定してやらなければ正しく機能しないようで、それならいっそ削除してしまっても(依存ライブラリでフィルタかけられなくても)いいだろう、という判断からです。
設定データは
[ワークスペース]/.recommenders/snipmatch/repositories/http___git_eclipse_org_gitroot_recommenders_org_eclipse_recommenders_snipmatch_snippets_git
でgit管理されていますので、間違って編集してしまった場合などでも簡単に元に戻せます。
また、同理由により設定の共有もさほど難しくないと思われます。

みんな本当にloggerをinjectionしたいなんて考えてるの?

CDIについてwebで検索していると、しばしばloggerをinjectするのが便利だと説明されているサイトに当たります。
以下に検索でヒットしたサイトの例と、そこに書かれているロガーをインジェクションすることのメリットあるいは動機を引用します。

ほとんどのサイトで、タイピングの手間が省けることがメリットであると書かれていました。
私からするとこの程度の手間の省略は、コンパイル時に解決できることを実行時まで遅延させる理由付けとしては弱すぎるように感じるのです。
世間一般的には十分受け入れられる動機なのでしょうか?
(例外からクラス名を取得するような手法を紹介されている方もいらっしゃいますが、これも同様に行うべきではないと私は考えています。)


単にタイプの手間を減らしたいだけであれば、私はIDEのスニペット機能を推奨します(次のエントリでEclipseの便利プラグインを紹介します。他のIDEでも似たような機能が有るでしょう)。
(ロギングのためだけに導入するのは首肯しかねますが、既に別の用途で導入済みであるなら)lombokの@Logアノテーションを用いてもコンパイル時に解決します。


JUL特有の問題の対策として、以下のように説明されている方がいらっしゃいました。
確かにコンパイル時には解決できないのでこのような理由でCDIを用いることには一理あると思いますが、一般的にはloggerはアプリケーション固有のクラスローダでロードする、すなわち設定は個別に行えるので一般的には当てはまらないと思います。
(そして更に言うと、一般的にはJULを使わない…ですよね?)


Java EE環境でjava.util.loggingとうまく付き合う方法 | Nishigaya's Tech Blog

複数のJava EEアプリが同一サーバ上に同居することを想定した場合、もう一つ注意すべき点があります。それは、「Loggerオブジェクトは、名前毎に生成されるJVMレベルでのシングルトン・オブジェクトである」ため、同居する複数のアプリが同じ名前のロガーを取得してしまうと、互いにロガーの設定に影響しあってしまう点です。先ほど、ロガー名にはパッケージ名を使用するのが望ましいということを述べましたが、異なるアプリでも共通のフレームワークやビジネスオブジェクト、バリューオブジェクトなどは同じクラス群をライブラリとして共通に使用するのが一般的で、そうするとどうしてもこれらのクラスについては、アプリが異なっても同じロガー名を使用してしまいます。せっかく、アプリ毎に異なるログファイルを設定しても、一方のアプリのログが他方のアプリのログに混じってしまうようなことが発生します。この問題を避けるためには、同じクラスを使ってもアプリ毎に必ず異なるロガー名が使われるようにしなければなりません。Java EE 6の環境であれば、アプリ名はJNDIリソースを通じてランタイムに取得することができますので、以下のようにして、ロガー名が”<アプリ名>.<パッケージ名>”のようにすることができます。

2015/10/10

Welding GWT-RPC with CDI @ConversationScoped

日本語の説明はこちら

Summary

For conversation propagation, request-parameter must have conversation-ID(cid).
Although, it is difficult to modify GWT-RPC request-body.
So, I try setting cid in request-header.
As a result, conversation is able to be propageted.

sample code(github)

Description

Environment:
  • Java1.8.0u60
  • Wildfly10Beta2(Weld2.3.0.CR1)
  • GWT(Google Web Toolkit) 2.7.0
For long-running conversation propagation, required "cid" parameter.
CDI1.2 spec:
6.7.4. Conversation context lifecycle
The long-running conversation associated with a request may be propagated to any Servlet request via use of a request parameter named cid containing the unique identifier of the conversation.
Weld doc:
5.3.2. Conversation propagation
We can force the conversation to propagate with a non-faces request by including the unique identifier of the conversation as a request parameter. The CDI specification reserves the request parameter named cid for this use.


Weld gets cid at ConversationContextActivator
And, we able to preprocess in Servlet Filter named "CDI Conversation Filter".
CDI1.2 spec:
6.7.4. Conversation context lifecycle
The container provides a filter with the name "CDI Conversation Filter", which may be mapped in web.xml, allowing the user alter when the conversation is associated with the servlet request.
There are also described:


Using custom filter, we able to create a request, not exist in request-body but providable cid.


Source shown at the beginning explain:
On GWT client side, set cid in header with RpcRequestBuilder.
On server side, define use of custom filter before CDI Conversation Fiter adaption with web.xml. Then, provide cid in header as request parameter with HttpServletRequestWrapper.

« 2015年9月 | トップページ

other sites

  • follow us in feedly
  • github
  • stackoverflow

ソフトウェアエンジニアとして影響を受けた書籍

  • Christain Bauer: HIBERNATE イン アクション

    Christain Bauer: HIBERNATE イン アクション
    理論と実践が双方とも素晴らしい製品であるHibernate。本書はそのプロダクトを書名に冠していますが、Hibernateを使うつもりがなく、ORマッピングの解説書として読むにしても十分な良書です。Second EditionとしてJava Persistence With Hibernateという書籍も出版されていますが、残念ながら現在のところ 和訳はされていません。-インアクションは2.xの、Java Persistence-は3.1の頃のものなので、最新版とはちょっと違うところもあることに注意。 (★★★★★)

  • アンドリュー・S・タネンバウム: 分散システム 原理とパラダイム 第2版

    アンドリュー・S・タネンバウム: 分散システム 原理とパラダイム 第2版
    クライアント/サーバシステムを構築する上で必要となる知識が総論されてます。Web技術者も、フレームワーク部分を開発するのであれば必読。 (★★★★★)

  • Joel Spolsky∥著: ジョエル・オン・ソフトウェア

    Joel Spolsky∥著: ジョエル・オン・ソフトウェア
    前述の書籍「ソフトウエア開発プロフェッショナル」をより砕いたもの、という感じでしょうか。 前書きではプログラマでなくSE向けの本のように書かれているが、プログラマが読んでも面白い本であると思われます。 SEになった新人(あるいはそういう会社に入る/入りたての人)にとっては、これからどういったことが仕事を遂行していく上で起こりえるのか、どのように考えて行なっていけばいいのか決定する助けになると思います。 元は″Joel on Software″というブログの記事で、web上でも一部日本語で読めます。 http://japanese.joelonsoftware.com/ (★★★)

  • ドナルド・C・ゴース,ジェラルド・M・ワインバーグ: ライト、ついてますか

    ドナルド・C・ゴース,ジェラルド・M・ワインバーグ: ライト、ついてますか
    問題解決(一昔前のの流行語で言うところの『ソリューション』)能力は、システムエンジニアのスキルとして備えるべきもののうちのひとつです。しかし、これは難しい。学校で出されるテストと違い、唯一の、(問題提出者が想定している)解を求めるだけが「問題解決」では無いからです。そもそも、何が問題なのか、それは本当に問題なのか、それは本当に解決すべき問題なのか、その問題解決方法は正しいのか、などを解決しなければ、「その解は正しいのか」に辿りつくことができません。この本の最も良いところのひとつは、本があまり厚くないこと。すぐに読めるし、何回も読み返す気になるでしょう。 (★★★★★)

  • スティーブ・マコネル: ソフトウエア開発プロフェッショナル

    スティーブ・マコネル: ソフトウエア開発プロフェッショナル
    コードコンプリートで有名なスティーブマコネルの著書。新人SEに読んで欲しい。個人として業界の中でどうあるべきか、組織としてどうあるべきか、SEのプロ意識とは?SEの心構え概論、といったところでしょうか。また、業界における資格の重要性についても説かれています。この業界では資格が特に軽んじられる傾向がありますが、この傾向はどんな弊害をもたらすのか、将来的にこの業界は資格に対してどのような姿勢で臨んでいくべきなのか。日経BP社では(他の出版社もだが)最近、似たような類いのあまり面白くない書籍が乱出版されていますが、この本は別格だと思うので安心して購入して欲しいと思います。 (★★★★★)

無料ブログはココログ