Wednesday, February 23, 2011

タグの中身の操作方法

XHTML/HTMLのタグの多くは内部に任意のタグまたは文字列を持つことができます(入れ子タグ)。 mixer2でのタグの中のタグ/文字列へのアクセスと操作方法の基本について解説します。

divやspanのように、中になんでも入れられるようなタグの場合は必ずプロパティとしてcontent(java.util.List型)を持っており、それに対するgetContent(), setContent(), unsetContent()で操作することができます。

例えば次のような形でテンプレートをloadしたと仮定します。

<html>
<head>
   <title>タイトルです</title>
</head>
<body>
    <div id="foo">aaa<b>bbb</b>ccc</div>
</body>
</html>
Html html = mixer2Engine.loadHtmlTemplate(new File("テンプレファイル"));
Div div = html.getById("foo",Div.class);
java.util.List list1 = div.getContent();

このとき、list1の内部は次のような値が格納されています。

添え字内容
0java.lang.Stringaaa
1org.mixer2.jaxb.xhtml.BBタグオブジェクト
2java.lang.Stringccc

list1はdivタグの中身の実体をList型で抱えていますので、あとは普通にList型を扱うように add(追加したいもの)、remove(消したいものの添え字)、set(添え字、置換物)等のメソッドで扱えます。

Html html = mixer2Engine.loadHtmlTemplate(new File("テンプレファイル"));
Div div = html.getById("foo",Div.class);
java.util.List list1 = div.getContent();

list1.add("ddd"); 
list1.set(1, new Br());
list1.remove(2);
System.out.println(m2e.saveToString(html));

上記によって、divタグの中を次のように書き換えたものを得ることができます。

<html>
<head>
<title>タイトルです</title>
</head>
<body>
<div id="foo">aaa<br />ddd</div>
</body>
</html>

Friday, February 18, 2011

モックhtmlの内容を操作する(アンカーリンク編)

通常のJava/JSPによるWeb開発では、htmlモックをJSPに書きなおす作業をします。この作業によって、Webデザイナーでは手が出せないような呪文が埋め込まれていきます。<form> が<html:form>になったり、<c:if test="${user.isLogin == true }" />こんにちは${user.name}さん!</c:if> と書き加えたりする、あの作業です。

JSPに書きなおす作業が発生し、さらにJSPに書き換えたが最後デザイナーはほとんど手が出せなくなる(うっかり修正してJSPの呪文を壊すとまずい)のですから、この工程に入った瞬間から開発現場の生産性はガタ落ちです。jspなのでアプリとして実行できる状態まで作業しないと、見栄えの確認も修正もできません。モックhtml作成のときのように「ちょっとブラウザで表示してみて見栄えを確認してまた修正する」といったことはできないのです。

そんな愚痴はさておき、ではmixer2ではそこをどう解決するのか?といったお話を少しずつ書いてゆきます。今日はアンカーリンク編です。aタグとformタグ(のaction属性等)についてお話しします。

たとえばテンプレート(htmlモック)に書いたaタグで
<a href="detail.html">
となっている箇所はすべて
<a href="/contextPath/foo/detail?id=99">
のような形に書き換えなければならない、と想定します。

この場合まず、テンプレートを作る段階で当該のaタグにid属性またはclass属性をつけておいてもらうのが早道です。

<a href="detail.html" id="detailLink" > ※このリンクがページ上に唯一ならid属性で
あるいは
<a href="detail.html" class="detailLink" > ※リンクがページ上に複数あるならclass
といった感じです。命名規則は特にありませんのでデザイナーとプログラマーの間で適当に取り決めておいてください。

テンプレート(htmlモック)をMixer2EngineでロードしてHtml型のオブジェクトに変換したら、次のようにします。

File file = ResourceUtil.getResourceAsFile("detail.html");
Html html = mixer2Engine.loadHtmlTemplate(file);
// id属性で走査して書き換え
html.getById("detailLink", A.class).setHref(
    request.getContextPath() + "/foo/detail?id=" + 99);
// class属性で走査してそれら全部を書き換え
for (A a : html.getDescendants("detailLink", A.class)) {
    a.setHref(request.getContextPath() + "/foo/detail?id=" + 99);
}

これで、該当のid属性またはclass属性を持つaタグのhref属性はすべて動的に書きかえられます。

formタグも同様です。htmlモック上では紙芝居のように画面遷移させるために
<form id="fooForm" method="get" action="thanks.html">
のようになっていたとすると、

html.getById("fooForm",Form.class).setAction(request.getContextPath() + "/foo/thanks");
html.getById("fooForm",Form.class).setMethod("post");

によって、
<form id="fooForm" method="post" action="/contextPath/foo/thanks">
に書き換えることができます。

Tuesday, February 15, 2011

coberturaのカバレッジ測定でignoreやexcludeがうまくできない

ちょっと番外、というか、愚痴です。

mixer2もちゃんとJUnitによる自動テストをやってます。テストケースの本数がまだ不足なのは否めませんが^^;)

カバレッジの測定もやっていまして、手元のeclipse上ではeclemmaプラグインで、mavenでのビルドとレポート生成時にはcoberturaを使っています。なんで違うソフトを使っているかと言うと、eclemmaにはmavenレポート用プラグインが無く、coberturaにはeclipse用プラグインが無いからです。どっちかに統一したいのはやまやまなんですが、そういうちぐはぐな状況なので仕方がありません。似たような事情を抱えているプログラマーさんも多いのではないでしょうか。

愚痴の本題なのですが、mavenのcoberturaプラグインには、特定の名称のパッケージ/クラスをカバレッジ測定対象にしない、という機能があるはずなのですが、うまく動かないようです。
バグレポートで言うとたぶん
[#MCOBERTURA-52] Ignores and Excludes do nothing - jira.codehaus.org
と同じ目に遭っているのだと思うのですが。

mixer2のとあるpackage配下は実はすべてJava6のJAXB-APIによる自動生成クラスなので、バグの混入の可能性がほとんどないクラスなので、カバレッジ測定対象から除外したいです。しかしそれがうまくいかなくて。

ちなみにいますべてのクラスがカバレッジゼロ%になっているのはこのバグだけでなく自分の単純ミスですww。 ほんとはもっとカバレッジ率あります。

Saturday, February 12, 2011

テンプレートhtmlをファイルじゃなくDBに保存できる

Webアプリのテンプレート、といえばJSPファイルです。しかし、mixer2ではカスタムタグ満載のjspではなく、デザイナーさんが作った普通のモックhtmlのファイルでOKです。

さらに、mixer2のテンプレートは、ファイルである必要すらありません。HelloWorldの例のようなjava.io.Fileオブジェクトだけでなく、Stringもテンプレートとして読み込めるからです。メソッドはloadHtmlTemplate(java.lang.String)です。

たとえばECサイト構築のASPサービスがあるとします。店舗ごとにまったく異なるデザインを見せるために、テンプレートは店舗ごとに異なるものを管理する必要があります。ブログサービスでも似たようなものですね。

店舗が10個くらいのうちはいいのですが、数百、数千となってくると、テンプレートをファイルで管理することが難しくなってきます。商品データ等と同様に、テンプレートもDB上で管理したくなってきます。

しかしJSPではテンプレートをDBで管理することは事実上困難です。Velocityも、DataSourceResourceLoaderによってテンプレートをDB管理することはできるものの、J2EEサポートを必要とするといった制約があり、使い勝手はあまりよくないようです。

しかしmixer2では単なるStringとして定義されたテンプレートhtmlを扱えます。
SAStrutsでのHelloWorldサンプルを、テンプレートをDBから読み込むとすると次のようになります。
// O/RマッパーとしてS2JDBCを使っていて、
// TEMPLATE_TABLEのTEMPLATEというカラムに
// テンプレートが保存されていると仮定します。
public class IndexAction {

    @Resource
    protected Mixer2Engine mixer2Engine;

    @Resource
    protected JdbcManager jdbcManager;

    public String htmlString;

    @Execute(validator = false)
    public String index() throws IOException, TagTypeUnmatchException {
        TemplateTable tt = jdbcManager
            .from(TemplateTable.class)
            .where(eq(id(),999))
            .getSingleResult();
        String templateString = tt.template;
        Html html = mixer2Engine.loadHtmlTemplate(templateString);
        html.getById("hellomsg", Div.class).unsetContent();
        html.getById("hellomsg", Div.class).getContent().add("Hello World!");
        htmlString = mixer2Engine.saveToString(html);
        return "index.jsp";
    }
}

以上、TIPSでした。

Friday, February 11, 2011

mixer2のサンプルアプリをつくってみました

まずはこちらをご覧ください。
http://mixer2.org/etc/nullpon-sastruts/src/main/webapp/list.html
画像を押すと詳細ページへ飛び、さらに「買う」を押すと、買ってくれてありがとう的な画面に移る、という、3画面だけのごく単純なアプリになっています。
この三つのファイルはいわゆる「モックhtml」などと呼ばれるものです。(だと思ってください、あくまでサンプルなんで^^;)
モックhtmlはWebデザインとしてはほぼ完成の状態であり、リンクやボタンを押せば次に想定される画面へ遷移できます。Webサーバ上にアップする必要も無く手元のPCのブラウザ上に読み込めば見れます。もちろんDBとの連携などありません。つまり「紙しばい」です。しかしそれはそれでOKです。モックhtmlはあくまでWebサイトとしての見た目、ユーザーインターフェースの確認の目的で作られるものだから、紙芝居でいいのです。

Webサイト開発の現場では、このモックhtmlをテンプレート言語(VelocityやJSP等)に書き直してWebアプリのView層にする、という作業の流れをよく見かけます。

しかし、mixer2を使うと「JSPに書き直す」という作業は不要です。モックHTMLのままでテンプレートとして使えるのがmixer2のメリットです。JSPのカスタムタグを書く必要はまったくありません。必要なのはXHTMLとCSSで書かれたモックHTMLファイルだけなのです。

http://mixer2.org/etc/nullpon-sastruts.tar.gzがこのWebアプリのアーカイブです。eclipse上にインポートすればすぐに稼動すると思いますのでお試しください。DBはsqliteを使っているのでDBの初期設定の手間もありません。

下記がこのサンプルアプリで想定している環境です。
  • Tomcat6
  • JDK1.6.0_22 (1.6.xなら何でも動くと思います)
  • eclipse 3.6.1(helios) + WTP2.5 (sysdeo使ってる人のほうが多いかもしれないんですけどWTPです、すいません。でもsysdeoプラグインでも動くと思います)
  • Seasar2/SAStruts/S2JDBCフレームワークをベースにしています。SAStrutsのビューはJSPやmayaaが使われることが多いようですが、それらの代わりにmixer2を使っている、と考えればいいでしょう。
基本的にはsiteのほうに書いてあるSAStrutsでのHelloWorldサンプルの応用編と言えます。

わかりやすくするために、ほとんどの実質的な実装をIndexActionクラスに集約してあります。

syntax highlighterのテスト

import java.io.File;
import org.mixer2.Mixer2Engine;
import org.mixer2.jaxb.xhtml.Div;
import org.mixer2.jaxb.xhtml.Html;

public class HelloWorld {

    public static void main(String[] args) throws Exception {
        Mixer2Engine m2e = new Mixer2Engine();
        Html html = m2e.loadHtmlTemplate(new File("HelloWorld.html"));
        html.getById("hellomsg",Div.class).unsetContent();
        html.getById("hellomsg",Div.class).getContent().add("Hello World !");
        System.out.println(m2e.saveToString(html));
    }

}

おお、なるほど。これは便利だな。
参考:クリボウの Blogger Tips: コードをハイライトする「Blogger Syntax Highlighter」ウィジェット

ブログはじめます

ブログはじめます。
mixer2 のことだけじゃなくて他の話題も書いていこうと思います。