<< < 1 2 3 4 > >>

Wicket本が届きました!


先日発売された日本初のWicket本が届きました。
著者の矢野さん、お疲れさまでした。

レビューに参加したということで、名前も載せていただきました。
技術本のレビューという、貴重な体験をさせてもらった上、本を頂けるとは感謝しきりです。

今夜は紅茶で祝杯です。


Wicketでパネルのユニットテスト

WicketにはWicket Testerと呼ばれるテストツールが付属しています。
サーブレットコンテナを起動せずにテストが出来る優れものですが、
今回、Wicketのパネルをテストしたときに、ちょっと癖があったのでメモしておきます。

Wicketのパネルとはいろんなコンポーネントとマークアップを一まとめにした部品です。
標準だとページャーを表示する部品、PagingNavigator なんかがあります。
パネルを使いまわすことができれば、コンポーネントの部品化は非常に進むと思います。
「部品化」が机上の空論にならないためにも、パネルとテストはどんどん活用したいですね。

今回は単純に現在時刻を表示するパネルを作ってみました。


テスト対象のパネルにはラベルが2つあるだけの単純なものです。
リポジトリにも置いてあります。
 public class TimerPanel extends Panel {
     /** serialVersionUID */
     private static final long serialVersionUID = 1L;

     public TimerPanel(String id) {
         super(id);
         add(new Label("label", getString("label")));

         IModel<String> model = new AbstractReadOnlyModel<String> () {
             /** serialVersionUID */
             private static final long serialVersionUID = 1L;

             @Override
             public String getObject() {
                 DateFormat format = DateFormat.getTimeInstance();
                 return format.format(new Date());
             }
         };
         Label timerLabel = new Label("timer", model);
         timerLabel.add(new AjaxSelfUpdatingTimerBehavior(Duration.ONE_SECOND));
         add(timerLabel);
     }
 }

これをテストするコードは下記になります。
これもリポジトリにも置いてあります。
 public class TestTimerPanel {
     private WicketTester tester;
     @BeforeMethod public void setup() {
         tester = new WicketTester();
     }

     @Test public void initDisplay() {
         tester.startPanel(new TestPanelSource() {
             private static final long serialVersionUID = 1L;
             public Panel getTestPanel(String panelId) {
                 return new TimerPanel(panelId);
             }
         });
         tester.assertComponent(DummyPanelPage.TEST_PANEL_ID, TimerPanel.class);
         tester.assertComponent(DummyPanelPage.TEST_PANEL_ID + ":label", Label.class);
         tester.assertLabel(DummyPanelPage.TEST_PANEL_ID + ":label", "現在の時刻");
         tester.assertComponent(DummyPanelPage.TEST_PANEL_ID + ":timer", Label.class);
     }
 }
startPanelメソッドにTestPanelSourceのインスタンスを渡します。
このクラスのgetTestPanelメソッドの戻り値として、テスト対象クラスのインスタンスを返すようにします。
パネルのwicket:idはDummyPanelPage.TEST_PANEL_IDとなります。このidを前提としてテストコードを書きます。

パネルのwicket:idがDummyPanelPage.TEST_PANEL_IDで固定になっている事を記載しているドキュメントは見つけられませんでした。
この点はドキュメントに書くべき部分でしょうね。

Wicketのウリ


DIを意識させたらキャズムは超えられない
難しいことをいってて損しているフレームワークは結構ある。
例えば、Wicketは、ステートフルがアピールポイントだと思うけど、
普通の人には、伝わりづらいと思うよ。
Javaで書けるってのも良さは伝わりづらいかな。
もっとわかりやすい、アピールポイントを見つけたほうがいいと思う。

まさにおっしゃる通りで、Wicketを説明する事がよくあるここ最近だけど、説明には結構困る。
間違ってもステートフルって単語は使えない。
DIについても同様で、やはりDIって単語をそのまま説明に使うことはできないですね。疎結合も同様。

SAStrutsはまだ試せてないけどTeedaとWicketを比べるとしたら、規約ではなくもっとJavaにより明示的なコンポーネント指向と言うべきか。。。。
こんな説明じゃぁ伝わらんよね。
そんなに Java やフレームワークをゴリゴリやっていない人にとってわかり易い部分をとりあげると、デザインとロジックの分離かと思ってそこを切り口にすることが多い。
けどまぁ Teeda やその他のフレームワークでも実現出きることでもあるんで、そんなにアピールポイントにならない。Strutsとならアドバンテージになるけど。
ちょっと技術を分かってる人だと、VB風とか説明をすると凄くわかってもらえる事があるけど、それがわかってもらえるのもVBをやってたりする一部の人だったりする。

Wicketの特徴をざっと挙げると、個人的にはこんな感じ。
  • 定義ファイルレス
  • JavaとHTMLの単純な構成
  • ホットデプロイ
  • ステートフル
  • 拡張性
眺めてみると、「ステートフル」をうまく説明するのが、Wicketの肝かなと思う。

難しい事をやさしく説明できる事が技術者としての自分の一つの目標なんで、非常にもどかしい所です。
もうちょっといろんな技術をかじって、語彙の引き出しを増やしたいなぁ。

Wicket Bits を試してみた


ちょっと前にメーリングリストでアナウンスのあったWicket Bitsを試してみました。
正確にはWicket Bits内の Automagic を試したのですが、どういう物かというと Wicketでお馴染みの wicket:idをHTMLに記述すると、Javaは特にいじらなくても自動的にコンポーネントを生成してくれる仕組みです。

使い方は簡単。まずWebapplicationクラスに下記を追加します。
    public void init() {
        this.addComponentOnBeforeRenderListener(new AutoCreateRenderListener());
    }
HTMLがこんな感じのとき、
<body>
<div wicket:id="label">Hoge</div>
</body>
Javaはこんな感じでOK。Labelを生成してaddしなくてもOKなんです。
private String label = "Hello !";
public HomePage() {
    setModel(new CompoundPropertyModel(this));
これだけで"Hello !"が表示されちゃいます。
仕組み的にはコンポーネントをRenderする前にタグと属性の型により、生成するコンポーネントを制御しています。
Wicket勉強会で話題になったらしいComponent Resolverを使っているわけではないようです。
タグとコンポーネントが結びついちゃってるってのは、ちょっと融通が聞きにくい部分なんですが、(例えばtableではなく、ulとかでListViewを使いたいとき)なかなか面白い試みですね。

まだまだできる事とできない事を調べ切れていないですが、ある意味割り切った形というのもアリですね。

Blogのデザインを変えました


Blogのデザインを変えてみました。
今回、HTMLベースのテンプレートを利用させてもらうことで、Wicketのウリの一つである、プログラムとデザインの分離による分業を擬似体験できました。
テンプレートを利用させてもらったのはこちら。
Styleshout.com

HTMLベースのテンプレートを組み込むのは大変簡単でした。
wicket:idさえ意識すれば、大体テンプレートの組み込みはできてしまいました。
ただ、行毎にスタイルを変えるようなデザイン部分についてはプログラマとデザイナのコミュニケーションが重要になりそうです。
例えば、以下のようなListViewクラス内のpopulateItemメソッドにおいて、CSSのclassを行毎に変えたりする場合です。
 protected void populateItem(final ListItem item) {
     if(item.getIndex() % 2 == 1) {
         item.add(new SimpleAttributeModifier("class", "alt"));
     }
 }
他にもwicket:enclosure等のWicket独自タグを意識する必要がありますが、JSP何かに比べれば大分簡単だと思います。

Wicket In Action Chapter11読了


Wicket社内勉強会2日目も昨日無事終わりました。
参加者には色々質問してもらえ、Wicketに少しでも興味を持ってもらえたようでなによりでした。

さてさて、Wicket In ActionのChapter11を読了しました。
この章は、Ajaxについて説明されています。
標準のAjaxコンポーネントの使い方から、仕組み、カスタムコンポーネントの作り方まで、Ajaxを使う上で必要な知識が網羅されてます。

このBlogもAjaxは全然使ってないですし、他でもAjaxを使う経験がなかったので新鮮でした。
Ajaxコンポーネントの存在は知ってたのですが、AbstractAjaxBehaviorを使うことで、結構簡単にAjaxを体験できるのは驚きでした。

下のコードは単純なLabelコンポーネントにAjaxSelfUpdatingTimerBehaviorを追加してAjax化した例です。
モデルの方で出力する文字列を制御するようにして、0.5秒毎に表示する文字列を切り替えてます。
 public class HelloWicket extends WebPage {
     public HelloWicket() {
         Label label = new Label("text", new EmojiModel());
         add(label);
         label.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(0.5)));
     }

     private static class EmojiModel extends AbstractReadOnlyModel {
         private int count = 0;
         private String[] emoji = new String[]{
                 "ε=ε=ε=ε\(*`∧´)/ ムッキー!!ε=┏(゚ロ゚;)┛ダ゙ッ!!",
                 "\(*`∧´)/ ムッキー!!ε=ε=┏(゚ロ゚;)┛ダダ゙ッ!!",
                 "\(*`∧´)/ ムッキー!!ε=ε=ε┏(゚ロ゚;)┛ダタダッ!!",
                 "\(*`∧´)/ ムッキー!!ε=ε=ε=ε=┏(゚ロ゚;)┛ダダダ゙ダッ!!",
                         "\(*`∧´)/ ムッキー!!ε=ε=ε=ε=ε=┏(゚ロ゚;)┛ダダダダッ!!"};
        
         @Override
         public Object getObject() {
             if (count >= emoji.length)
                 count = 0;
             return emoji[count++];
         }
     }
 }

Ajax系のコンポーネントはwicket-stuffにも結構あるし、Ajaxをお手軽に体験するという点でもWicketはお薦めですね。
そのうちこのBlogもAjaxをもうちょっと取り入れていこうかと思います。

Wicket in Action Table of Contents
Part 1 Getting started with Wicket
1. What is Wicket?
2. The architecture of Wicket
3. Setting up a Wicket project
4. Building a cheesy Wicket application

Part 2 Getting a basic grip on Wicket
5. Understanding models
6. Using basic components
7. Using forms for data entry
8. Composing your pages

Part 3 Advanced Wicket
9. Creating custom components
10. Working with Wicket resources
11. Rich components and Ajax
12. Authentication and authorization
13. Localization
14. Multi-tiered architecture
15. Putting your application in production
16. Component index

Wicket社内勉強会をやりました


ひょんな事から社内教育を行うことになった。
お題はWicket。
簡単なWicketの紹介をプレゼンして、実際にWicketでアプリを書いてもらうハンズオン形式の社内教育にしました。

レベル的にはあまりWebアプリを知らなくて、Javaはそこそこできる人間が対象でした。
そんなわけで、JavaでのWebアプリケーションの歴史を追う意味でも、Servlet、Struts、Wicket で同じ仕様のアプリをソースレベルで比較、解説してみるってコーナーも設けました。
私自身、Webフレームワークを使わないServletのみの現場と言うのは未経験ですし、
Strutsは経験あるけども、既にWicketで書いたコード量の方が多いぐらいでそんなに分かっていませんでしたので大変勉強になりましたね。

久々StrutsやServletでアプリを書いた経験は貴重でした。
「やっぱ設定ファイルだるいなー」とか、「やっぱJSP嫌いだなー」ってのを再実感できたし、
Servletのみの構成で作ってみると、「Strutsていいなー」とあらためて実感できたり。
技術の進歩をこじんまりと実体験できた気がします。
参加者もその辺を感じ取ってもらえたようです。

講師を引き受けてみて、こういうプレゼンとかセミナーでは一番講師が得している事が実感できました。
やっぱり人に教えるといういい意味でのプレッシャーがあるといいですね。
質問も違う視点での疑問点が聞けて非常にためになる。

Wicketを広めるという点では、JSP嫌いの子がかなり食いついてくれたようで好感触でしたので、ひとまず成功ということで!

Wicket In Action Chapter10読了


この暑いさなかWii Fitを汗だくになってやってるんで、ちょっと更新が滞ってましたが、Wicket In Action Chapter10読了しました。

この章は、イメージファイルやPDF等のリソースをWicketで扱う方法が書かれています。
自分としてはリソースはあまりわかっていなかったので、大変参考になりました。
業務チックなところでは、CSVの出力なんかにも関わってくるところです。

リソースを扱う方法は大きく分けると以下の3つの方法になります。
  • 画像であればImageコンポーネントやResourceLinkコンポーネントを使う方法。
  • Applicationクラスで管理するSharedResourceを用いる方法。
  • RequestTargetに直接リソースを設定する方法。

試しにこのBlogの横っちょにある「カテゴリ一覧」にImageコンポーネントを使ってアイコンをつけてみました。
「カテゴリ一覧」はListViewを使って実装しています。populateItemメソッド内に以下を追加します。
protected void populateItem(final ListItem categoryItem) {
    categoryItem.add(new Image("icon", new ResourceReference(CategorySummary.class, "icon.png")));
CategorySummaryクラスと同じパッケージ内にicon.pngというファイル名でイメージファイルを置いておけば、イメージが表示されます。
ちなみにHTMLはこんな感じ
<span wicket:id="categorySummaryList" class="categorySummary">
    <img wicket:id="icon" src="icon.png" /> <a href="#" class= "categorySummary" wicket:id="categoryLink"><span wicket:id="category">category</span></a><br />
</span>

この辺りの知識は、リソースを扱うPanel等を作るときには重要になりそうですね。

Wicket in Action Table of Contents
Part 1 Getting started with Wicket
1. What is Wicket?
2. The architecture of Wicket
3. Setting up a Wicket project
4. Building a cheesy Wicket application

Part 2 Getting a basic grip on Wicket
5. Understanding models
6. Using basic components
7. Using forms for data entry
8. Composing your pages

Part 3 Advanced Wicket
9. Creating custom components
10. Working with Wicket resources
11. Rich components and Ajax
12. Authentication and authorization
13. Localization
14. Multi-tiered architecture
15. Putting your application in production
16. Component index

Wicket In Action Chapter8読了


娘が風邪でてんやわんやの中、飛ばしてたChapter8をやっと読了。

この章はコンポーネントのグループ化とページレイアウトについての説明になります。
コンポーネントのグループ化では、Panel, WebMarkupContainer, Fragment、ページのレイアウトについては、Panel, wicket:extend のそれぞれについて具体的な例が示されて大変わかりやすいです。
個人的にはそんなに新しい知識はなかったのですが、 Wicket を初めて知ったときに wicket:extend でページが継承できるとしって感動した事を思い出しました。
このおもしろさはなかなか他のフレームワークでは味わえないんじゃないでしょうか?

さてさて、この章で興味深かったのはページのレイアウトをPanelで構成するかwicket:extendで構成するかを考察している部分でした。
Wicketで作ったこのBlogもそうだけど、基本的には wicket:extend で構成してます。
個人的にはページのヘッダ部やメニューバー等を構成するにあたってはPanelよりwicket:extendが好みです。
一つのWebページクラスでリンクの押下をトリガにメインコンテンツ部のPanelを切り替える方法もありますが、制御が複雑になるために本著でも切り替えは2つのPanelまでだろうと述べられています。
また、複数WebページクラスにPanelを追加していくにしても、結局Panelインスタンスをaddするコードが複数箇所にあらわれちゃうんですよね。
抽象化した部品を構成するにはPanelは威力を発揮するでしょうが、ページを構成するにはむいてないんじゃないかなぁと思ってます。

Wicket in Action Table of Contents
Part 1 Getting started with Wicket
1. What is Wicket?
2. The architecture of Wicket
3. Setting up a Wicket project
4. Building a cheesy Wicket application

Part 2 Getting a basic grip on Wicket
5. Understanding models
6. Using basic components
7. Using forms for data entry
8. Composing your pages

Part 3 Advanced Wicket
9. Creating custom components
10. Working with Wicket resources
11. Rich components and Ajax
12. Authentication and authorization
13. Localization
14. Multi-tiered architecture
15. Putting your application in production
16. Component index

Wicket In Action Chapter9読了


またまた仕事の都合で先にChapter9のカスタムコンポーネントを読むことにした。

画面部品の再利用を効果的に行うにあたってのノウハウが満載のこの章ですが、特に勉強になったのは FormComponentPanel でした。
このクラスは Panel に似た使い方ができるのですが、使う側から見たら TextField の様な一つのコンポーネントだけど、内部的には複数のコンポーネントで構成されている Formコンポーネントを作成するのに使用します。
例として掲載されているコードは、外部から見たら Date型の値をModelとするコンポーネントだけど、内部的には 年月日、時間、分のTextFieldを持っているカスタムコンポーネントです。
onBeforeRenderメソッドで与えられたModelの値を内部の各コンポーネントに振り分け、convertInputメソッドで外部に渡すModelの値を構成するようにします。

試しに作ってみたのは、内部的には 姓・名 をもつコンポーネント。
外部から見ると姓・名 を空白で区切った値をやりとりするんだけど、内部的には別々のフィールドとして定義されています。
 import org.apache.wicket.markup.html.form.FormComponentPanel;
 import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.PropertyModel;

 public class CustomForm extends FormComponentPanel {
     private String firstName;
     private String lastName;
     private String name;
     private TextField firstNameField;
     private TextField lastNameField;

     public CustomForm(String id) {
         this(id, null);
     }
     public CustomForm(String id, IModel model) {
         super(id, model);

         add(firstNameField = new TextField("first", new PropertyModel(this, "firstName"), String.class));
         add(lastNameField = new TextField("last", new PropertyModel(this, "lastName"), String.class));
     }
     @Override
     protected void onBeforeRender() {
         name = (String) getModelObject();
         if (name != null) {
             if (name.split("\\s").length == 2 ) {
                 lastName = name.split("\\s")[1];
                 firstName = name.split("\\s")[0];
             }
         }
         firstNameField.setRequired(isRequired());
         lastNameField.setRequired(isRequired());
         super.onBeforeRender();
     }

     @Override
     protected void convertInput() {
         setConvertedInput(firstNameField.getInput() + " " + lastNameField.getInput());
     }
 }
使う側としては、下記のようにして一つのコンポーネントとして使用します。
form.add(new CustomForm("name", new Model("Hoge Fuga")));
onBeforeRenderメソッドで"Hoge Fuga"がCustomFormクラス内部のfirstName, lastNameフィールドにセットされます。
Submitされた時は、convertInputメソッドでfirstNameFieldの値とlastNameFieldの値が空白で区切って結合され、外部からはこの値が見えます。

この辺の画面部品の作りやすさはさすが Wicket って感じです。


Wicket in Action Table of Contents
Part 1 Getting started with Wicket
1. What is Wicket?
2. The architecture of Wicket
3. Setting up a Wicket project
4. Building a cheesy Wicket application

Part 2 Getting a basic grip on Wicket
5. Understanding models
6. Using basic components
7. Using forms for data entry
8. Composing your pages

Part 3 Advanced Wicket
9. Creating custom components
10. Working with Wicket resources
11. Rich components and Ajax
12. Authentication and authorization
13. Localization
14. Multi-tiered architecture
15. Putting your application in production
16. Component index