Dec 26, 2005

[Misc] 2005 年のまとめ

あと数日で 2005 年も終わり。 というわけで、2005 年に話題になったトピックの中で個人的に興味深かったものをまとめてみた。 Web 系アプリケーション開発(特に Java)に関係するものが中心。

2005 年のトピック TOP5

  1. 個人情報保護 & 情報漏洩
  2. Web サービス
  3. Ajax
  4. Web2.0
  5. 新しい開発用ツール
個人的な TOP 5 はこの辺り。 この辺りを抑えておけば個人的には満足なので、後でそれぞれおさらいしよう。

個人情報保護法 & 情報漏洩

個人的には個人情報保護法関連が一番インパクトが大きかった。 困るのは、個人情報保護が従来のセキュリティ(XSS 脆弱性対策、セッションライディング対策、SQL Injection対策)とは異なるレイヤーに属していること。 セキュリティを今までよりも高いレイヤーで取り扱う必要が出てきた。 これは意外と大変なことになる気がする。後々、色々と。

個人情報保護法が施行されてから、個人情報の取り扱いが劇的に変わった。 さて、個別のシステムではこの動きにどう対応していく必要があるのか。 今後の大きな課題。

後は、Winny絡みの個人情報 & 機密情報の漏洩。 原発、警察、保険会社など色々なところからありえない様な情報が何度も漏洩した。 システム開発とは関係ないけれど、技術者の端くれとしては色々と考えさせられた。

個人情報の保護に関する法律の概要
http://www5.cao.go.jp/seikatsu/kojin/gaiyou/index.html
個人情報の保護に関する法律(平成一五年五月三十日法律第五十七号)
http://www5.cao.go.jp/seikatsu/kojin/houritsu/index.html
個人情報保護法の解説
http://www5.cao.go.jp/seikatsu/kojin/kaisetsu/index.html
Google 先生による情報漏えい事例集
http://www.google.com/search?q=%2B%E6%83%85%E5%A0%B1+%2B%28%E6%BC%8F%E3%81%88%E3%81%84+OR+%E6%B5%81%E5%87%BA%29+%2BWinny

Web サービス

Web サービスが一気に面白くなってきた気がする。 WSDL、UDDI、SOAP云々の技術話ではなく、Google Maps、del.icio.us API 等々。 それなりにサービスが揃ってきたので、色々と工夫のしがいが出てきた感じがする。

Google
http://www.google.com/apis/
Yahoo!
http://developer.yahoo.co.jp/search/
Technorati
http://www.technorati.com/developers/
del.icio.us
http://del.icio.us/help/api/
はてな
http://www.hatena.ne.jp/info/webservices
Bidders
http://blog.dena.ne.jp/bws/
Flicker
http://flickr.com/services/api/

Ajax

Ajax が大きな流れになった。 リッチクライアントを駆逐するかとも思えるくらいの勢いになってきたので少々驚いている感じ。 個人的には、お遊びで使うにはいいけれど・・・という感想。 どうも Ajax は HTML 4.01 に対する付け焼刃な気がする。 HTML 5 で部分更新だの何だのを規格に取り込んでほしい。 HTML 5 は策定されないのだろうか??

新しい開発用ツール

Eclipse 3.1系3.2系Maven 2 が大きかった。 後は Continuum などの Maven 関連ツール。 開発環境に欲しい機能は十分以上にフリーで揃うようになった。 Maven2 辺りは思い通りにカスタマイズできるレベルまで遊び倒しておきたい。

Web2.0

2005 年の Buzz Word 大賞か。 単なるビジネス話だと感じるので、とりあえずは多少追いかけておけば良いかな、という感じ。

What Is Web 2.0
http://www.oreillynet.com/pub/a/oreilly/tim/news/2005/09/30/what-is-web-20.html
Web 2.0:次世代ソフトウェアのデザインパターンとビジネスモデル(前編)
http://japan.cnet.com/column/web20/story/0,2000054679,20090039,00.htm

その他 & 総括

  • ハードウェア系は縮小路線な感じがした。とりあえずは一段落なのだろうか??
  • OS も静かだった。個人的には Debian Sarge のリリースだけだった。
  • サービス系が元気だった。Mixi、Google 各種サービス、Amazon なか見検索、iTunes等々。



私の 2005 年はそんな一年だった。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 20, 2005

[Misc] GeoURL にチャレンジ

GeoURL とは

GeoURL は、地理情報とサイトを連携するサービス。 GeoURL にサイトを登録すると、そのサイトの "地理的に" 近いサイトが分かる。 余り意味があるとも思えないが、ご近所さんのサイトが分かるということがメリットなのだろうか。 面白そうなので試してみた。

GeoURL
http://geourl.org/
GeoURL - サイトの追加方法
http://geourl.org/add.html

GeoURL にサイトを登録

  1. 位置情報を決定する
    まずは、登録する位置情報を決定する。どういう方法でも良いが、緯度と経度が必要。ここでは Google Map を利用する。

    Google Map にアクセスして、適当に場所を選択する。場所が決まったら、「このページへのリンク」というリンクの URL を見る。 "http://maps.google.com/maps?ll=35.665865,139.893090&spn=0.006252,0.005015&hl=ja" の様な URL になっているはず。 この中で、"ll=35.665865,139.893090" の部分が緯度と経度の情報になるのでメモしておく。
  2. サイトに情報を埋め込む
    HTML の HEAD ブロックに以下の様な META タグを埋め込む。
    <meta name="ICBM" content="35.66586, 139.89309">
    <meta name="DC.title" content="in-vitro.jp">
    ICBM の値は Google Map でメモした値そのままで良い。但し、桁数が違うので、小数以下を 5 桁にする。 DC.title の値はサイトの名前を指定する。
  3. GeoURL へ PING を打つ
    GeoURL - PINGでサイトの URL を入力して PING!!
  4. ご近所さんを確認
    PING を打つと http://geourl.org/near?p=[サイトの URL] でご近所さんが分かるようになる。
ちなみに、このサイトのご近所さんはこちら→in-vitro.jp のご近所さん

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 18, 2005

[WebService] del.icio.us API にチャレンジ

del.icio.us API とは

ソーシャル・ブックマークサービスの del.icio.us が公開している API。 ブックマークの登録、削除などの操作ができる。 方式は Yahoo! 同様 REST を採用している。

del.icio.us
http://del.icio.us/
del.icio.us - Reference
http://del.icio.us/help/api/

試してみる

試してみた。

  1. 最初に del.icio.us トップ から del.icio.us のアカウント登録を行う。
  2. リクエスト用の URL を作成する。
  3. 早速リクエストを送ってみる。リクエスト URL 実行時に BASIC 認証によるログインが要求されるので 1 で登録したアカウントで認証を行う。

ブックマークの登録

http://del.icio.us/api/posts/add?url=http://www.in-vitro.jp/blog/index.cgi/index.rss&description=in-vitro.jp
<?xml version='1.0' standalone='yes'?>
<result code="done" />

ブックマークの取得

http://del.icio.us/api/posts/get?
<?xml version='1.0' standalone='yes'?>
<posts dt="2005-12-16" tag="" user="invitro.jp">
  <post href="http://www.in-vitro.jp/blog/index.cgi/index.rss" 
           description="in-vitro.jp" 
           hash="e885a76a691ce90ff1626c1bd5c41a26" 
           others="1" 
           tag="system:unfiled" 
           time="2005-12-17T14:44:59Z" />
</posts>

ブックマーク先 URL の取得指示

http://del.icio.us/api/posts/update
<?xml version='1.0' standalone='yes'?>
<update time="2005-12-17T14:54:38Z" />

ブックマークの削除

http://del.icio.us/api/posts/delete?url=http://www.in-vitro.jp/blog/index.cgi/index.rss
<?xml version='1.0' standalone='yes'?>
<result code="done" />

del.icio.us 呼び出し用 HTML

Google Web APIs (beta) にチャレンジ で使用した HTML を BASIC 認証に対応させて使用した。

<html>
<head>
<script>
<!--
  var req;

  function sendRequest() {
    var url = document.myform.url.value;
    var param = document.myform.request.value;
    var username = document.myform.username.value;
    var password = document.myform.password.value;

    req = prepareXMLHttpRequest();
    if (req == null) {
      alert('XMLHttpRequest is not supported');
      return;
    }

    var encodedParam = '';
    var splitParam = param.split('&');
    for(i = 0; i < splitParam.length; i++) {
      var tmp = splitParam[i].split('=');
      encodedParam += '&' + encodeURIComponent(tmp[0]) + '=' + encodeURIComponent(tmp[1]);
    }

    req.onreadystatechange = showResponse;
    if(username != null && password != null) {
      req.open("POST", url, true, username, password);
    } else {
      req.open("POST", url, true);
    }
    req.setRequestHeader("Content-Type" , "text/xml");
    req.send(encodedParam);
  }

  function showResponse() {
    if (req.readyState == 4) {
      if (req.status == 200) {
        document.myform.response.value = req.responseText;
      } else {
        document.myform.response.value = 'FAILURE!! ' + req.status + ':' + req.statusText;
      }
    }
  }

  function prepareXMLHttpRequest() {
    if (window.XMLHttpRequest) {
      return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      return new ActiveXObject("Microsoft.XMLHTTP");
    }
    return null;
  }
//-->
</script>
</head>

<body>
  <form name="myform">
    <input type="button" value="POST!!" onclick="sendRequest();"><br>
    <br>
    URL: <input type="text" name="url" size="100"> <span style="font-size: xx-small;">[REQUIRED]</span><br>
    USERNAME: <input type="text" name="username" size="30"> <span style="font-size: xx-small;">[OPTIONAL]</span><br>
    PASSWORD: <input type="text" name="password" size="30"> <span style="font-size: xx-small;">[OPTIONAL]</span><br>
    <br>
    REQUEST: <span style="font-size: xx-small;">[OPTIONAL]</span><br>
    <textarea name="request" cols="100" rows="25"></textarea><br>
    <br>
    RESPONSE:<br>
    <textarea name="response" cols="100" rows="25"></textarea>
  </form>
</body>
</html>

Posted in WebService | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 17, 2005

[WebService] Yahoo! 検索 Web サービスにチャレンジ

Yahoo! 検索 Web サービスとは

Yahoo! が公開している検索用 API。 Google は SOAP を採用しているが、それに対し Yahoo! は REST(HTTP リクエストに対して XML レスポンスが返される) を採用している。 Yahoo! が SOAP ではなく REST を採用した理由は、「なぜYahoo! JAPAN WebサービスはRESTを使用しているのですか? 」に記載されている。 対応しているサービスは、ウェブ検索、画像検索、動画検索。

Yahoo! 検索 Web サービス
http://developer.yahoo.co.jp/search/
Yahoo! 検索 Web サービス - Reference
http://developer.yahoo.co.jp/search/web/V1/webSearch.html

試してみる

試してみた。 リクエストの送信に使用した HTML は Google Web APIs (beta) にチャレンジ で使用したものと同じ。

  1. 最初に アプリケーション ID の登録 を行う。登録には Yahoo! ID が必要。
  2. リクエスト用の URL を作成する。クエリに 1 で取得したアプリケーション ID を指定する必要がある。例) "http://api.search.yahoo.co.jp/WebSearchService/V1/webSearch?appid=[アプリケーションID]&query=Yahoo%20Web%20Search"
  3. 早速リクエストを送ってみる。2 で作成した URL を呼び出す。
[Yahoo! 検索 Web サービス の呼び出し]

Posted in WebService | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 16, 2005

[WebService] Google Web APIs (beta) にチャレンジ

Google Web APIs (beta) とは

Google が公開している Webサービス用の API。 Google に SOAP でリクエストを送ると、SOAP レスポンスで処理結果が帰ってくる。 対応しているサービスは、キャッシュの取得、検索、スペルチェック。

Google Web APIs (beta)
http://www.google.com/apis/
Google Web APIs (beta) - Reference
http://www.google.com/apis/reference.html
License
http://www.google.com/apis/api_terms.html

試してみる

試してみた。 Google Web APIs の呼び出し方は色々あるが、とりあえず今回は直接 POST でリクエストを送り込むことにする。 POST の送信に使用した HTML は↓に添付する。

  1. 最初に Google Web APIs license key の取得 を行う。
  2. リクエスト用の SOAP メッセージを作成する。メッセージには 1 で取得したライセンスキーを埋め込む必要がある。Google Web APIs Developer's Kit をダウンロードするとサンプルの SOAP メッセージが入っているので、それを参考にするとラク。
  3. 早速リクエストを送ってみる。"http://api.google.com/search/beta2" に対して 2 で作成した SOAP メッセージを送信する。
[Google Web APIs の呼び出し]

Google Web APIs 呼び出し用 HTML

POST の送信には JavaScript を利用して ajax っぽく(笑)してみることに。

<html>
<head>
<script>
<!--
  var req;

  function sendRequest() {
    var url = document.myform.url.value;
    var param = document.myform.request.value;

    req = prepareXMLHttpRequest();
    if (req == null) {
      alert('XMLHttpRequest is not supported');
      return;
    }

    req.onreadystatechange = showResponse;
    req.open("POST", url, true);
    req.setRequestHeader("Content-Type" , "text/xml");
    req.send(param);
  }

  function showResponse() {
    if (req.readyState == 4) {
      if (req.status == 200) {
        document.myform.response.value = req.responseText;
      } else {
        document.myform.response.value = 'FAILURE!! ' + req.status + ':' + req.statusText;
      }
    }
  }

  function prepareXMLHttpRequest() {
    if (window.XMLHttpRequest) {
      return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      return new ActiveXObject("Microsoft.XMLHTTP");
    }
    return null;
  }
//-->
</script>
</head>

<body>
  <form name="myform">
    <input type="button" value="POST!!" onclick="sendRequest();"><br>
    <br>
    URL:<br>
    <input type="text" name="url" size="100"><br>
    <br>
    REQUEST:<br>
    <textarea name="request" cols="100" rows="25"></textarea><br>
    <br>
    RESPONSE:<br>
    <textarea name="response" cols="100" rows="25"></textarea>
  </form>
</body>
</html>

検索用 SOAP リクエスト(サンプル)

<?xml version='1.0' encoding='UTF-8'?>

<SOAP-ENV:Envelope 
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/1999/XMLSchema">

  <SOAP-ENV:Body>
    <ns1:doGoogleSearch xmlns:ns1="urn:GoogleSearch" 
         SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <key xsi:type="xsd:string">[Google Web APIs license key]</key>
      <q xsi:type="xsd:string">Google Web APIs</q>
      <start xsi:type="xsd:int">0</start>
      <maxResults xsi:type="xsd:int">10</maxResults>
      <filter xsi:type="xsd:boolean">true</filter>
      <restrict xsi:type="xsd:string"></restrict>
      <safeSearch xsi:type="xsd:boolean">false</safeSearch>
      <lr xsi:type="xsd:string"></lr>
      <ie xsi:type="xsd:string">latin1</ie>
      <oe xsi:type="xsd:string">latin1</oe>
    </ns1:doGoogleSearch>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Posted in WebService | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 15, 2005

[Misc] Unicode の取り扱いについて (3)

結局、Unicode を使う場合には

  1. 文字列を OS に渡すと JVM と異なる認識をすることがある。
  2. OS における Unicode のサポート状況により、OS 毎に挙動が異なる。
    (しかも、OS の種類が同一でもインストール時のオプションによって差異が出ることがある)
という問題があることが分かった。

というわけで、安全でない文字列をパスとして利用する場合はかなり様々な注意が必要となる。 HTML に Unicode 系の文字エンコーディングを指定している Web アプリケーションは要注意。 パスとして利用できる文字列は「半角英数字のみ」くらいの厳しい制約をかけておくのが無難だろう。 OS のシステムの文字エンコーディングが Unicode 系でない場合は、OS のシステムの文字エンコーディングで表現できる文字、くらいの縛りでも良いかもしれない。


「本来文字コードでフォレンジックに関係しそうな領域はそれほど広くないはずだが、実際には非常に深い世界で、変な深海魚のようなものが出てくる(笑)」と語り、今後この分野はさらに研究が必要であるとの見解を示して講演を終えた。

(http://pcweb.mycom.co.jp/articles/2005/11/07/blackhat/001.htmlより抜粋)


ということなので、判定を厳しくしておくに越したことはなさそう。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 13, 2005

[Misc] Unicode の取り扱いについて (2)

昨日のコードを今度は Debian(Sarge) で動かしてみた。

実験環境

  • Debian Sarge
  • Java 1.5.0_05

実行結果

[エクスプローラの表示]

実験環境の Sarge はシステムの文字エンコーディングを EUC-JP でインストールしているので、当然のように Unicode 制御文字は '?' 扱いとなった。 結局何が言えるかというと、同じコードでも OS 毎に挙動が異なるということ。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 12, 2005

[Misc] Unicode の取り扱いについて

ついでに以前読んで気になっていた Unicode 問題も試してみた。 ここでは、Unicode 制御文字や似通ったグリフを持つ文字を利用して「表示上」簡単に区別できない文字列を生成出来てしまうことが問題点として取り上げられている。

Black Hat Japan 2005 - Unicode文字によるDirectory Traversal攻撃
http://pcweb.mycom.co.jp/articles/2005/11/07/blackhat/

実験環境

  • Windows XP Professional
  • Java 1.5.0_05

サンプルコード

public static void main(final String[] args) {

    File file0 = new File("dummy"); // "dummy"
    File file1 = new File("dummy\ufeff"); // "dummy"の後に表示されない文字を付加
    File file2 = new File("\u202eymmud\u202c"); // "ymmud"を逆に表示

    System.out.println("" + file0.mkdirs());
    System.out.println("" + file1.mkdirs());
    System.out.println("" + file2.mkdirs());
}

実行結果

[エクスプローラの表示]
エクスプローラでは全く見分けが付かない("dummy" に見える)ディレクトリが 3 つ作成された。

[CMDの表示]
cmd で見ると違うディレクトリであることが分かる。

というわけで、簡単に利用者を欺くようなファイル/ディレクトリを生成できてしまった。 具体的にどういう被害が想定できるか思いつかないが、いたずらくらいは簡単に出来てしまいそう。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 09, 2005

[Misc] File アクセス時における Unicode の取り扱いについて

遅ればせながら、産総研グリッド研究センター 高木浩光さんによる「安全なWebアプリ開発の鉄則2005」を読んだ。 その中に実は全く認識していなかった問題があったので、Java の環境で実際に起こり得るのか確かめてみた。 「安全なWebアプリ開発の鉄則」の 2005 年度版は Web 上で公開されていないようなので、↓は 2004 年度版へのリンク。 同様の記述は既に記載されている。

安全なWebアプリ開発の鉄則2004
http://www.nic.ad.jp/ja/materials/iw/2004/proceedings/T5.pdf

実験内容

"c:\tmp\dummy.txt\u0000.html" というファイルを読み込んだ際に、ファイルシステム上で実際に読み込まれるのはどのファイルなのかをチェックする。 拡張子を String#endsWith でチェックして・・・というのはありがちな処理。 "c:\tmp\dummy.txt" が読み込まれてしまうと拡張子チェックをすり抜けてしまうことになるので、セキュリティホールの原因になる。

実験環境

  • Windows XP Professional
  • Java 1.5.0_05
  • c:\tmp\dummy.txt を作成し "this file is c:\tmp\dummy.txt" と書き込んである
  • c:\tmp には dummy.txt 以外のファイルは存在しない

サンプルコード

public static void main(final String[] args) throws IOException {

    String fileName = "c:\\tmp\\dummy.txt\u0000.html";
    File file = new File(fileName);

    System.out.println("Exists: " + file.exists());
    System.out.println("Absolute Path: " + file.getAbsolutePath());
    System.out.println("ends with \".html\": " + file.getAbsolutePath().endsWith(".html"));

    FileReader fr = null;
    BufferedReader br = null;
    try {
        fr = new FileReader(fileName);
        br = new BufferedReader(fr);
        String line = null;

        System.out.println();
        while ((line = br.readLine()) != null) {
            System.out.println("" + line);
        }
    } finally {
        try {
            if (br != null) {
                br.close();
            }
        } finally {
            if (fr != null) {
                fr.close();
            }

        }
    }
}

実行結果

Exists: true
Absolute Path: c:\tmp\dummy.txt□.html
ends with ".html": true

this file is c:\tmp\dummy.txt

・・・というわけで

パスに '\u0000' が入ると、JVM と OS で認識するファイルが異なってしまうことが分かった。 ユーザ入力の文字列をパスの一部として利用するような場合は注意が必要となる。

それにしても、あっさりと自分の認識不足が露呈してしまったorz ファイル名をユーザー入力にする場合はかなり気をつけねば。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 06, 2005

[Misc] Web アプリケーションのセキュリティに関する情報源をメモ

Web アプリケーションのセキュリティに関するリソースをリストアップ。 オンラインコンテンツだけでも結構な量なので、書籍はとりあえずパス。

リンク集

セキュリティエンジニアリング
http://www.ipa.go.jp/security/awareness/vendor/software.html
(無断リンク、ディープリンク禁止なのでリンクしない)

一般論 - 総合

The World Wide Web Security FAQ
http://www.w3.org/Security/Faq/001031wwwsfj.ja.sjis.html
Web アプリケーションの脆弱性 トップ10 2004 Update
http://prdownloads.sourceforge.net/owasp/OWASP_Top_Ten_2004_Japanese.pdf?download
WEBセキュアプログラミング ~脆弱性を作らないWEBアプリ開発~
http://www.soi.wide.ad.jp/class/20020036/slides/19/index_1.html
インターネットセキュリティに関する RFC の日本語訳
http://www.ipa.go.jp/security/rfc/RFC.html
JNSAセキュアシステム開発ガイドライン 「Webシステム セキュリティ要求仕様(RFP)」編 β版
http://www.jnsa.org/active/2005/active2005_1_4a.html
ISO/IEC 15408 の翻訳文書
http://www.ipa.go.jp/security/jisec/evalbs.html
RFC 2109 - HTTP State Management Mechanism (4.2.2 に Cookie の secure 属性に関する記述)
http://www.ietf.org/rfc/rfc2109.txt

一般論 - クロスサイトスクリプティング脆弱性

Webサイトにおけるクロスサイト スクリプティング脆弱性に関する情報
http://www.ipa.go.jp/security/ciadr/20011023css.html
クロスサイトスクリプティング攻撃に対する電子商取引サイトの脆弱さの実態とその対策
http://securit.gtrc.aist.go.jp/research/paper/css2001-takagi-dist.pdf
Cross-Site Scripting Vulnerabilities
http://www.cert.org/archive/pdf/cross_site_scripting.pdf
なぜCSSXSSに抜本的に対策をとることが難しいか
http://tdiary.ishinao.net/20060331.html#p01

一般論 - クロスサイトリクエストフォージェリ

クロスサイトリクエストフォージェリ(CSRF)の正しい対策方法
http://takagi-hiromitsu.jp/diary/20050427.html#p01
CSRF - クロスサイトリクエストフォージェリ
http://d.hatena.ne.jp/hoshikuzu/20050130#D20050130CSRF
開発者のための正しいCSRF対策
http://www.jumperz.net/texts/csrf.htm

プログラミング - Java

セキュア・プログラミング講座
http://www.ipa.go.jp/security/awareness/vendor/programming/index.html
セキュア・プログラミング講座 2- J2EE
http://www.ipa.go.jp/security/fy14/contents/trusted-os/programming-2.pdf
Software Vulnerabilities in Java
http://www.sei.cmu.edu/publications/documents/05.reports/05tn044.html

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 05, 2005

[Misc] UI に関する情報源をメモ

UI に関する情報源をメモ。 とりあえずアクセシビリティもユーザビリティもごちゃ混ぜ。 意外と書籍が多いので、どれを購入しようか悩む。

オンラインコンテンツ

Jacob Nielsen 博士の Alertbox
http://www.usability.gr.jp/alertbox/
useit.com: Jakob Nielsen's Website
http://www.useit.com/
WEB STYLE GUIDE, 2nd edition
http://www.webstyleguide.com/index.html?/contents.html
User Interface Design and Development
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/anch_uidesigndev.asp
桑原政則オンライン ウェブアクセシビリティのページ
http://www.aoikuma.com/webevaluationpg.htm
ユーザインターフェースデザイン研究室
http://www.phenomena.co.jp/phenomena/uid_lab/index.html
富士通ウェブ・アクセシビリティ指針
http://jp.fujitsu.com/webaccessibility/
JIS X 8341
http://www.jisc.go.jp/app/pager?id=120242&NEXKN_vJISJISNO=X8341

書籍(和書・洋書)

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 03, 2005

[Misc] 青空文庫に貢献したい

青空文庫は著作権の切れた作家の作品をボランティアで入力・校正して公開してくれているサイト。 「著作権が切れたから皆の共有財産にしよう」という活動は本当に有り難い。 何かお手伝いしてみたいとは思っているのだが、なかなか継続的にリソースを確保するのも難しいので二の足を踏んでいる。 ここは一つコーダーらしいお手伝いをしてみよう、ということで青空文庫用のブラウザを作ってみた。

青空ブラウザ

↓のリンクをクリックすると青空ブラウザが起動する。
青空ブラウザを起動

青空ブラウザ 使用上の注意

このソフトは・・・

  1. オレオレ証明書で署名されている。 → 正式な証明書を所有していない && 署名しないとセキュリティ制約で動作しないため
  2. 外部へのネットワークアクセスを要求する。 → 青空文庫にアクセスするため
  3. ムヤミヤタラと使用して青空文庫に無用な負荷をかけないよう注意が必要
このソフトを利用する際には・・・
  1. J2SE 5.0 以上の JVM が必要。
  2. ネットワークのアクセス権限が必要。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Dec 01, 2005

[Misc] iPod をデフラグメンテーションする

面白いネタを知った→HOW TO MAKE YOUR IPOD FASTER(ネタ元 iPodをデフラグして高速化する方法)
iPod をデフラグすると動作が速くなるらしい。 フォーラムの書き込みをざっと眺めてみると、Windows のデフラグツールでも OK らしい。 まぁ、iPod とは言え実際のところは単なるマスストレージ対応の HDD だし。 というわけで、実際に試してみた。

使用した iPod / OS

iPod
第 5 世代 iPod (いわゆる Video iPod) 60G ← FAT32 でフォーマットされたもの
OS
Windows XP Professional

デフラグの風景

[お馴染み、ドライブのプロパティ] 普通にエクスプローラから iPod のプロパティを表示。
[分析終了] とりあえず分析。デフラグの必要は無いと言われるがメゲずに開始。
[デフラグ終了] デフラグ終了。手元の環境では約 30 分程かかった。

結果

デフラグ自体は何の問題もなく終了。 デフラグ後も動作に問題はなさそう。まだ確信を持って言える状況ではないけれど。 動作速度は体感できるレベルで改善された。 具体的には、メニューの切り替わりがキビキビするようになった。 今まではメニュー画面切り替え時につっかかるような挙動をしていたのだが、デフラグ後はそれがなくなった。 意外にデフラグの効果が大きかった。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 28, 2005

[Maven] maven-metadata.xml の読み込み方

先日作成した MavenRepositoryBrowser で使用した maven-metadata.xml の読み込み方法をメモ。

maven-metadata.xml 読み込みの実行環境構築

  1. maven-repository-metadata-2.0.jar をクラスパスに追加。
  2. plexus-utils-1.0.4.jar をクラスパスに追加。

サンプルコード

org.apache.maven.artifact.repository.metadata.Metadata というクラスが Metadata を表す。 ストリーム等から maven-metadata.xml を読み込み Metadata を生成するのが org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader。 この 2 つのクラスを利用すると苦も無く maven-metadata.xml を読み込むことができる。便利。

    public Metadata readMetadata(final String groupId,
            final String artifactId, final String version) throws Exception {
        String mavenMetadataRelativePath = "/" + groupId.replaceAll("\\.", "/")
                + "/" + artifactId + "/" + version + "/" + "maven-metadata.xml";
        String repositoryRootPath = this.repositoryRoot.toExternalForm();
        if (!repositoryRootPath.endsWith("/")) {
            repositoryRootPath = repositoryRootPath + "/";
        }

        URL mavenMetadataURL = new URL(repositoryRootPath
                + mavenMetadataRelativePath);
        Metadata metadata = this.readMetadata(mavenMetadataURL);
        return metadata;
    }

    protected Metadata readMetadata(final URL url) throws Exception {

        Metadata metadata = null;
        InputStream is = null;
        Reader source = null;
        try {
            URLConnection connection = url.openConnection();
            is = connection.getInputStream();
            source = new InputStreamReader(is);

            MetadataXpp3Reader reader = new MetadataXpp3Reader();
            metadata = reader.read(source);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } finally {
                if (source != null) {
                    source.close();
                }
            }
        }
        return mavenMetadata;
    }

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 27, 2005

[Maven] pom.xml の読み込み方

先日作成した MavenRepositoryBrowser で使用した pom.xml の読み込み方法をメモ。

pom.xml 読み込みの実行環境構築

  1. maven-model-2.0.jar をクラスパスに追加。
  2. plexus-utils-1.0.4.jar をクラスパスに追加。

サンプルコード

org.apache.maven.model.Model というクラスが POM を表す。 ストリーム等から pom.xml を読み込み Model を生成するのが org.apache.maven.model.io.xpp3.MavenXpp3Reader。 この 2 つのクラスを利用すると苦も無く pom.xml を読み込むことができる。便利。

    public Model readModel(final String groupId, final String artifactId,
            final String version) throws Exception {

        // Maven2 リポジトリのディレクトリ構成に合わせて URL を生成。
        String pomRelativePath = "/" + groupId.replaceAll("\\.", "/") + "/"
                + artifactId + "/" + version + "/" + artifactId + "-" + version
                + ".pom";
        String repositoryRootPath = this.repositoryRoot.toExternalForm();
        if (!repositoryRootPath.endsWith("/")) {
            repositoryRootPath = repositoryRootPath + "/";
        }

        // pom.xml の読み込み。
        URL pomURL = new URL(repositoryRootPath + pomRelativePath);
        Model model = this.readModel(pomURL);

        return model;
    }

    protected Model readModel(final URL url) throws Exception {
        Model model = null;
        InputStream is = null;
        Reader source = null;
        try {
            // 指定された URL からデータを取得
            URLConnection connection = url.openConnection();
            is = connection.getInputStream();
            source = new InputStreamReader(is);

            // pom.xml の解析
            MavenXpp3Reader reader = new MavenXpp3Reader();
            model = reader.read(source);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } finally {
                if (source != null) {
                    source.close();
                }
            }
        }
        return model;
    }

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 24, 2005

[Maven] Maven2 のリポジトリにある jar の依存関係を見たい!!

Maven2 はリポジトリに各種ライブラリが揃っていて有難いのだが、 jar 同士の依存関係は各々の pom ファイルに散っているので意外と追いかけづらい。 「struts-1.2.4.jar が依存しているライブラリをとりあえず見てみたい」等という状況になると、 struts-1.2.4.pom を見て → commons-beanutils-1.6.1.pom を見て → commons-logging-1.0.pom を見て・・・ と頑張って辿ることになる。 段々面倒になってきたので、リポジトリ内の pom の依存関係を追いかけるツールを作ってみた。

Maven2 Repository Browser

↓のリンクをクリックすると Java Web Start で Maven2 Repository Browser が起動する。
Maven2 Repository Browser を起動

とりあえず半日ちょいで作ったお気軽ツールなので、マトモに動くかどうか不明。 動かない場合は諦めが肝心。ちなみに Maven1 のリポジトリは面倒なので未対応。

Maven2 Repository Browser 使用上の注意

このソフトは・・・

  1. Maven2 のリポジトリから pom ファイルを読み込み、dependencies を追いかける。
  2. オレオレ証明書で署名されている。 → 正式な証明書を所有していない && 署名しないとセキュリティ制約で動作しないため
  3. 外部へのネットワークアクセスを要求する。 → Maven2 のリポジトリにアクセスするため
このソフトを利用する際には・・・
  1. J2SE 5.0 以上の JVM が必要。
  2. ネットワークのアクセス権限が必要。
  3. Maven2 の知識が必要。

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 23, 2005

[Misc] Java Web Start メモ

Java Web Start に関してちょっと調べてみた。 簡単にメモ。

Java Web Start 公式サイト
http://java.sun.com/products/javawebstart/index.jsp
Java Web Start Architecture JNLP Specification
http://java.sun.com/products/javawebstart/download-spec.html
Java Forums - Java Web Start & JNLP
http://forum.java.sun.com/forum.jspa?forumID=38

JNLP ファイルさえ書ければ簡単に Java Web Start アプリケーションを構築できる。 ただ、JNLP ファイルが意外と落とし穴だったりする。 JNLP ファイルの DTD は Java Web Start の仕様書(JSR-56) に記載されている。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 20, 2005

[Misc] コンテンツ移動のお知らせ

http://www.in-vitro.jp/blog/index.cgi/Misc/20051120_01.html はこちらに移動しました。
Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

[VMWare] VMWare Player のサービス停止

Windows XP Professiona に VMWare Player をインストールしたら、ログイン後の処理にやたらと時間がかかるようになった気がする。 タスクマネージャでプロセスを見てみると、

  • vmnat
  • vmnetdhcp
  • vmware-authd
というプロセスが常駐している。これが重いのかもしれない(←本当かどうかは分からない)。 このプロセスを止めてしまうと VMWare Player を起動したときにゲスト OS の動作に支障が出るので、必要なときにだけ起動するようにしたい。

とりあえず↓の様なバッチを作って必要なときに起動するようにした。 しばらくこれで様子を見てみよう。

startVMWareService.bat

net start "VMWare Authorization Service"
net start "VMWare DHCP Service"
net start "VMWare NAT Service"
stopVMWareService.bat
net stop "VMWare NAT Service"
net stop "VMWare DHCP Service"
net stop "VMWare Authorization Service"

Posted in VMWare | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 19, 2005

[Book] A Practical Guide to Feature-Driven Development (The Coad Series)

書籍情報


A Practical Guide to Feature-Driven Development (The Coad Series)

レビュー

アジャイルプロセスの一つである FDD(Feature Driven Development) の解説書。 FDD の基本は当然押さえてあるのだが、"Practical Guide" と銘打っているだけあって報告書のサンプルから開発者のロール毎のアドバイスなど有用な情報が多い。 FDD は、アジャイルプロセスの中ではバランスが良いようなので一読しても損はない。 訳書も出ている(
アジャイル開発手法FDD―ユーザ機能駆動によるアジャイル開発
)が、非常に残念なことに訳者が・・・orz 非常に残念。

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 17, 2005

[Library] tinySQL にチャレンジ

tinySQL とは

tinySQL は Pure Java の RDBMS。 どうも何かの書籍で使用されたサンプルアプリケーションらしい。 色々試してみたのだが、結局 insert が全く動作しなかった。 当然 select、update、delete も試しようがない。 というわけで、あっさりと使い物にならないことが判明。 まぁ、書籍のサンプルだし。
とりあえず create table、drop table だけは動作した。 ↓はそのサンプルコード。意味はないけれども。

tinySQL
http://sourceforge.net/projects/tinysql/

tinySQL の実行環境構築

  1. tinySQL(tinySQL.jar) ver.2.0 をクラスパスに追加

サンプルコード

package jp.in_vitro.codelets.tinysql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Codelet {

    public Codelet() throws ClassNotFoundException {
        super();
    }

    public static void main(final String[] args) throws SQLException,
            ClassNotFoundException, InstantiationException,
            IllegalAccessException {
        Codelet me = new Codelet();
        me.execute();
    }

    protected void execute() throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {

        this.initializeDBMS();
        try {
            try {
                // テーブルの生成。
                this.createTable();
            } catch (SQLException e) {
                // 既に Table が生成済みの可能性があるので・・・
            }
            
            // insert が全く動作しないので、select、update、delete も試しようがない・・・
            
            // テーブルの削除。
            this.dropTable();
        } finally {
            this.destroyDBMS();
        }
    }

    protected void initializeDBMS() throws ClassNotFoundException {
        Class.forName("com.sqlmagic.tinysql.textFileDriver");
    }

    protected void destroyDBMS() {

    }

    protected Connection getConnection() throws SQLException {
        String url = "jdbc:tinySQL";
        return DriverManager.getConnection(url);
    }

    protected void createTable() throws SQLException {
        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("CREATE TABLE sample (field01 INT)");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }

    }

    protected void dropTable() throws SQLException {
        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("DROP TABLE sample");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }
}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 10, 2005

[Misc] 影舞のレポートを CSV 形式でエクスポートしたい

影舞は RSS もサポートしているし統計も自前で表示してくれるのスグレモノなのだけれど、事情により CSV 形式のエクスポートもしたい。 ということで、影舞に少し手を入れてみた。 Ruby は初めてなので「とりあえず動く」レベルの仕上がり(^^;

ダウンロード

影舞用CSV出力プラグイン

動作環境

このプログラムは下記の環境で動作する。

  • Debian Sarge
  • 影舞 0.8.6

インストール方法

  1. export_csv.rb を $KAGEMAI_HOME/lib/kagemai/cgi/action にコピー
  2. export_csv.rhtml を $KAGEMAI_HOME/resource/ja/template/_default にコピー
  3. http://localhost/kagemai-0.8.6/html/admin.cgi?project=myproject&action=export_csv にアクセスして動作確認を行う

出力例

下記の様な感じで、「レポートID、レポート作成日時、レポート更新日時、メッセージID、報告者、状態、処理方法、優先度、重大度、担当者」というフォーマットの CSV が出力される。

1,2005/11/08 01:53:09,2005/11/08 01:53:24,1,myaccount@example.com,新規,未処理,緊急,重大,未定,
1,2005/11/08 01:53:09,2005/11/08 01:53:24,2,myaccount@example.com,新規,未処理,緊急,重大,未定,
2,2005/11/08 02:11:19,2005/11/08 02:11:19,1,myaccount@example.com,新規,未処理,中,普通,未定,
3,2005/11/08 02:11:34,2005/11/08 02:11:34,1,myaccount@example.com,新規,未処理,中,普通,未定,

カスタマイズ方法

出力する項目をカスタマイズしたい
export_csv.rb を適当に編集してください
CSV ファイルにコメントを付加したい
export_csv.rhtml を適当に編集してください

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 09, 2005

[Maven] Continuum にチャレンジ

Continuum とは

Continuum は、Maven2、Maven、Ant などに対応した継続的インテグレーションツール。 実際のところはシェルスクリプトをキックできるようになっているので、他のビルドツールを使用していても大丈夫。 Apache Maven プロジェクトの一環として開発が行われている。 先日ついにバージョン 1.0 がリリースされたので実際に試してみた。

Continuum 公式サイト
http://maven.apache.org/continuum/

Continuum の実行環境構築

JDK(1.4以上) 及び開発に使用している JDK、SCM クライアント、ビルドツールが既にインストールされていることが前提。

  1. ダウンロードページから continuum-1.0-bin.tar.gz をダウンロード
  2. Continuum をインストール
    # tar zxvf ./continuum-1.0-bin.tar.gz
    # mv ./continuum-1.0 /opt
    # ln -s /opt/continuum-1.0/ /opt/continuum
    
  3. JAVA_HOME を設定
    # export JAVA_HOME=/opt/jdk15
    # export PATH=$JAVA_HOME/bin:$PATH
    # java -version
    java version "1.5.0_05"
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
    Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode, sharing)
    
  4. /opt/continuum/bin/linux/run.sh の先頭の方に "PATH=/opt/maven2/bin:$PATH" を追記(開発に Maven2 を使っている場合)。
  5. Continuum を起動する。初回起動にはかなり時間がかかる(Pen4 2.4G 上の VMWare で数分かかった)ので気長に待つ。2 回目からは速くなるのでじっとガマン。
    # /opt/continuum/bin/linux/run.sh console
    
    ※run.sh のパラメータには通常 start を使用するが、初回はエラーが出る可能性があるのでフォアグラウンドで実行される console を使用すると便利。
  6. http://localhost:8080/continuum/ にアクセスして動作確認を行う。初回起動時に管理者用アカウントの設定画面が表示される。
    [管理者用アカウント設定画面] [初期画面]

Continuum へのプロジェクトの追加

Maven2 + Subversion で管理しているプロジェクトを Continuum に追加してみる。

pom.xml の編集

pom.xml に scm と ciManagement を追記する。

<model>
  <scm>
    <connection>scm:svn:http://svn.example.com/repos/MyProject/trunk/</connection>
    <developerConnection>scm:svn:http://svn.example.com/repos/MyProject/trunk/</developerConnection>
    <url>http://svn.example.com/repos/MyProject/</url>
  </scm>

  <ciManagement>
    <system>continuum</system>
    <notifiers>
      <notifier>
        <type>mail</type>
        <configuration>
          <address>me@example.com</address>
        </configuration>
      </notifier>
    </notifiers>
  </ciManagement>
</model>

Continuum へ pom.xml を登録

"Add Project" > "Maven 2.0+ Project" で pom.xml をアップロードする。
[pom.xml のアップロード] [プロジェクトが登録されたところ]

ビルドの実行

"Continuum" > "Show Projects" から該当プロジェクトの "Build Now" をクリックして強制的にビルドを実行する。
[ビルド結果一覧]

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 08, 2005

[Misc] 影舞にチャレンジ

影舞とは

Ruby 製の Bug Tracker。 名前で分かる通り国産。素晴らしい!!

影舞 公式サイト
http://www.daifukuya.com/kagemai/
影舞のインストール方法
http://www.daifukuya.com/kagemai/doc/install.html
インストール中に参考にしたのはこちら↓
[kagemai-users:0343] Re: コンフィグファイルとsafe
http://www.daifukuya.com/kagemai/ml/users/msg00343.html
[kagemai-users:0438] Ruby/MySQL 0.2.5 での影舞の利用について
http://www.daifukuya.com/kagemai/ml/users/msg00438.html

インストールメモ

影舞を Debian Sarge にインストールしたときのインストールメモ。 GD 周りでいくつかパッケージを調べたりしたけれど、基本的には非常に簡単だった。 後でもう一度構築する可能性があるのでとりあえずメモを残しておく。 それにしても、VMWare Player は中々調子が良い。 素晴らしい!!

# uname -a
Linux debian-sarge 2.6.8-2-386 #1 Thu May 19 17:40:50 JST 2005 i686 GNU/Linux

  1. 下準備
    Apache2 のインストール
    # apt-get install apache2
    
    Ruby のインストール
    # apt-get install ruby1.8
    # apt-get install libapache2-mod-ruby
    
    Apache2 の設定
    • /etc/apache2/apache2.conf にある AddHandler cgi-script .cgi のコメントアウトを外す。
    • /etc/apache2/sites-available/default にある /var/www/ 用の Directory の設定で Options に ExecCGI を追加する。
  2. 影舞のインストール
    インストール
    # tar zxvf ./kagemai-0.8.6.tar.gz
    # mv ./kagemai-0.8.6 /var/www
    # chown -R www-data:www-data /var/www/kagemai-0.8.6
    # chmod 755 /var/www/kagemai-0.8.6/html/*.cgi
    
    確認
    http://localhost/kagemai-0.8.6/html/guest.cgi にアクセスしてみる。
  3. MySQL のインストール
    インストール
    # apt-get install mysql-server-4.1
    # apt-get install libdbd-mysql-ruby1.8
    
  4. 影舞のデータベース設定
    影舞用のデータベースを作成
    # mysql
    mysql> create database kagemai;
    Query OK, 1 row affected (0.01 sec)
    
    mysql> grant all on kagemai.* to kagemai@localhost;
    Query OK, 0 rows affected (0.01 sec)
    
    影舞の設定変更
    影舞の管理メニューから"全体の設定の変更"を選択して下記の通り設定。
    • enable_mysql=true
    • mysql_host=localhost
    • mysql_port=3306
    • mysql_user=kagemai
    • mysql_pass=
    • mysql_dbname=kagemai
  5. グラフ出力用設定
    GD, GDChart インストール
    # apt-get install libgd-ruby1.8
    # apt-get install libgdchart-gd2-xpm
    
    Ruby/GDChart インストール
    1. http://sourceforge.jp/projects/ruby-gdchart/ から ruby-gdchart-0.0.9-beta.tar.gz をダウンロード
    2. Ruby/GDChart をコンパイル
      # tar zxvf ./ruby-gdchart-0.0.9-beta.tar.gz
      # cd ruby-gdchart-0.0.9-beta
      # apt-get install ruby1.8-dev ・・・ require 'mkmf' を解決するために ruby1.8-dev を入れる
      # apt-get install libgd-dev ・・・ ruby/gdchart のコンパイルに必要なので libgd-dev を入れる
      # ruby extconf.rb
      # make
      # make install
      
    日本語フォントインストール
    # apt-get install ttf-kochi-gothic ttf-kochi-mincho ttf-sazanami-gothic ttf-sazanami-mincho
    
    影舞の設定変更
    影舞の管理メニューから"全体の設定の変更"を選択して下記の通り設定。
    • enable-gdchart=true
    • gd-font=/usr/share/fonts/truetype/kochi/kochi-gothic.ttf
    • gd_chasert=UTF-8
Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 06, 2005

[Library] JExcelAPI の概要

JExcelAPI のクラス図

JExcelAPI 2.5.8 の「イイカゲン」なクラス図を作ってみた。

[JExcelAPI 2.5.8 のクラス図]

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 05, 2005

[Library] JExcelAPI にチャレンジ

JExcelAPI とは

JExcelAPI は、 MS Excel の Workbook を Java で扱うライブラリ。 Workbook の読み込み/書き出しからシートの印刷設定まで様々な機能を持っている。 Jakarta POI も同様の機能を持っているが、POI は PowerPoint/Excel/Word に対応しているのに対し JExcelAPI は Excel だけに絞っているので Excel を使うだけなら JExcelAPI の方が楽。 何も手を入れなくても、日本語がきちんと通るみたいなので嬉しい。

JExcelAPI
http://jexcelapi.sourceforge.net/
JExcelAPI のチュートリアル
http://www.andykhan.com/jexcelapi/tutorial.html

JExcelAPI の実行環境構築

  1. JExcelAPI(jxl.jar) をクラスパスに追加(ここではバージョン 2.5.8 を利用)。

サンプルコード

package jp.in_vitro.codelets.jexcelapi;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import jxl.BooleanCell;
import jxl.Cell;
import jxl.CellType;
import jxl.Sheet;
import jxl.Workbook;
import jxl.format.PageOrientation;
import jxl.format.PaperSize;
import jxl.read.biff.BiffException;
import jxl.write.Boolean;
import jxl.write.DateTime;
import jxl.write.Label;
import jxl.write.Number;
import jxl.write.WritableCell;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import jxl.write.biff.RowsExceededException;

public class Codelet {

    public Codelet() {
        super();
    }

    public static void main(final String[] args) throws IOException,
            RowsExceededException, WriteException, BiffException {
        File inputFile = new File("c:\\template.xls");
        File outputFile = new File("c:\\output.xls");
        Map<String, String> data = new HashMap<String, String>();
        data.put("bookname", "Object Design");

        Codelet me = new Codelet();
        me.createBook(inputFile);
        me.mergeBook(inputFile, outputFile, data);
    }

    public void createBook(final File target) throws IOException,
            RowsExceededException, WriteException {

        WritableWorkbook book = Workbook.createWorkbook(target);
        WritableSheet sheet = book.createSheet("sheet0", 0);
        sheet.setPageSetup(PageOrientation.PORTRAIT, PaperSize.B5, 1.0, 1.0);

        // line 0
        sheet.addCell(new Label(0, 0, "TODO"));
        sheet.addCell(new Label(1, 0, "期限"));
        sheet.addCell(new Label(2, 0, "優先度"));
        sheet.addCell(new Label(3, 0, "完了"));
        // line 1
        sheet.addCell(new Label(0, 1, "ANSI COMMON LISP を読む"));
        sheet.addCell(new DateTime(1, 1, new Date(System.currentTimeMillis())));
        sheet.addCell(new Number(2, 1, 1));
        sheet.addCell(new Boolean(3, 1, false));
        // line 2
        sheet.addCell(new Label(0, 2, "${bookname} を読む"));
        sheet.addCell(new DateTime(1, 2, new Date(System.currentTimeMillis())));
        sheet.addCell(new Number(2, 2, 2));
        sheet.addCell(new Boolean(3, 2, false));

        book.write();
        book.close();
    }

    public void mergeBook(final File inputFile, final File outputFile,
            final Map<String, String> data) throws BiffException, IOException,
            RowsExceededException, WriteException {

        Workbook inputBook = Workbook.getWorkbook(inputFile);
        WritableWorkbook outputBook = Workbook.createWorkbook(outputFile);

        Sheet[] inputSheets = inputBook.getSheets();
        for (int k = 0; k < inputSheets.length; k++) {
            Sheet inputSheet = inputSheets[k];
            WritableSheet outputSheet = outputBook.createSheet(this.merge(
                    inputSheet.getName(), data), k);
            outputSheet.setPageSetup(PageOrientation.PORTRAIT, PaperSize.B5, 1.0, 1.0);

            for (int i = 0; i < inputSheet.getRows(); i++) {
                for (int j = 0; j < inputSheet.getColumns(); j++) {
                    Cell inputCell = inputSheet.getCell(j, i);
                    CellType inputCellType = inputCell.getType();
                    WritableCell outputCell = null;
                    if (inputCellType == CellType.LABEL) {
                        outputCell = new Label(j, i, this.merge(inputCell
                                .getContents(), data));
                    } else if (inputCellType == CellType.BOOLEAN) {
                        outputCell = new Boolean((BooleanCell) inputCell);
                    } else if (inputCellType == CellType.NUMBER) {
                        outputCell = new Number(j, i, new BigDecimal(inputCell
                                .getContents()).doubleValue());
                    } else if (inputCellType == CellType.DATE) {
                        outputCell = new DateTime(j, i, new Date());
                    }
                    outputSheet.addCell(outputCell);
                }
            }
        }

        outputBook.write();
        outputBook.close();
    }

    protected String merge(final String target, final Map<String, String> data) {

        if (target == null || "".equals(target)) {
            return "";
        }

        int prefixIndex = target.indexOf("${");
        int suffixIndex = target.indexOf("}");
        if (-1 < prefixIndex && prefixIndex < suffixIndex) {
            String key = target.substring(prefixIndex + "${".length(),
                    suffixIndex);
            String value = data.get(key);
            return target.replaceAll("\\$\\{" + key + "\\}", value);
        } else {
            return target;
        }
    }
}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 04, 2005

[Misc] コンテンツ移動のお知らせ

http://www.in-vitro.jp/blog/index.cgi/Misc/20051104_01.html はこちらに移動しました。
Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

[VMWare] VMWare Player にチャレンジ

VMWare Player とは

PC エミュレータの VMWare に、無償版の VMWare Player があるらしい。 "Player" と銘打っているだけあって仮想イメージを作成する機能がなく、実際に利用するためには仮想イメージを作成できる製品版の VMWare Workstation が必要とのこと。

でも、逃げ道があった。→ 本当に無償で使える「VMware Player」 素晴らしい!! というわけで早速チャレンジ。

VMWare Player のインストール

↑の "Weboo! Returns" さんの説明通りで困ることも無くさくっと終了。

追加で調べたところだけ少しメモ。

qemu-img のコマンド

仮想イメージの作成に利用する QEMU のコマンド qemu-img について。

>qemu-img create -f vmdk d:\debian-sarge.vmdk 4G

qemu-img で指定できるコマンド

  • create
  • commit
  • convert
  • info

対応ファイルフォーマット

create 時に -f オプションで指定可能なファイルフォーマットは

raw
Raw disk image format (default).
qcow
QEMU image format, the most versatile format.
cow
User Mode Linux Copy On Write image format.
vmdk
VMware 3 and 4 compatible image format.
cloop
Linux Compressed Loop image, useful only to reuse directly compressed CD-ROM images present for example in the Knoppix CD-ROMs.
らしい。今回は VMWare で動かすことが目的なので vmdk のみを使用しているみたい。

qemu-img info

仮想イメージの情報を表示するコマンドは何故か動作しなかった(エラーで落ちる)。

>qemu-img info -f vmdk d:\debian-sarge.vmdk

仮想イメージの複数登録

仮想イメージを複数登録する場合、以下の手順で行う (OS は Debian を想定)。

  1. 新しいイメージを作成。
    >qemu-img create -f vmdk d:\debian-sarge2.vmdk 10G
  2. debian-sarge.vmx に以下を追加(/deb/hdb に追加する場合)。
    ide0:1.present = "TRUE"
    ide0:1.fileName = "debian-sarge2.vmdk"
  3. Debian を起動
  4. /deb/hdb の primary 1 にパーティション(タイプは Linux)を作成。
    #fdisk /dev/hdb
  5. EXT3 でパーティションをフォーマット。
    #mke2fs -j /dev/hdb1
  6. 作成したパーティションをテストする。
    #mkdir /mnt/test
    #mount -t ext3 /dev/hdb1 /mnt/test
    #umount /mnt/test
    #rmdir /mnt/test
後は /etc/fstab を適当に編集。

ゲスト OS あれこれ

指定可能な questOs

Galileo Computing さんによると、vmx ファイルの guestOS の値は以下のものが利用できるらしい。

Guest OS 名 vmx の guestOS
Windows Server 2003 Standard Edition winnetstandard
Windows XP Professional winxppro
Windows 2000 Professional win2000Pro
Red Hat Linux (generic) redhat
SuSE Linux (generic) suse
Netware 5 netware5
Netware 6 netware6
Solaris 9 solaris9
Solaris 10 (experimental) solaris10
FreeBSD (generic) freebsd
Other Linux otherlinux
Other Linux 2.4x kernel other24xlinux
Other Linux 2.6x kernel other26xlinux

ゲスト OS のインストール時メモ

というわけで色々なゲスト OS を入れてみたので、そのときのメモ。 全て最小インストールを選択し、X Window などの GUI はインストールしていない。 インストールは全て Daemon Tools で直接 ISO をマウントして行った。

Debian Sarge
questOs="other24xlinux" でインストールは何事もなく終了。"apt-get install kernel-image-2.6.8-2-386" をしてみたが問題なく動作した。Kernel のアップデート前から
atkbd.c: Unknown key released (translated set 2, code 0x01 on isa0060/serio0).
atkbd.c: Use 'setkeycodes e001 ' to make it known.
というエラーが出る。Kernel アップデート後も変わらず。但し、コンソール上にエラーが表示されるだけで実害はナシ。なんだろう、これ??
[Debian Sarge]
Solaris 10
questOs="solaris10" でインストールは何事もなく終了。DHCP クライアントでネットワークの設定を行うと、ホスト名が正常に設定されない。修正方法は
  1. /etc/nodename にホスト名(FQDN)を書く
  2. /etc/hostname.pcn0 にホスト名を書く
  3. #uname -S ホスト名
  4. #reboot
[Solaris 10]
Fedora Core4
questOs="other26xlinux" でインストールは何事もなく終了。その後も特に問題なし。guestOs="redhat" もあるけれど、どちらが良いのだろう??
[Fedora Core 4]
FreeBSD 5.4
questOs="freebsd" でインストールは何事もなく終了。ホスト名、ネットワークは /etc/rc.conf に以下の通り設定した。
hostname=ホスト名
ifconfig.lnc0="dhcp"
[FreeBSD 5.4]

Posted in VMWare | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Nov 01, 2005

[Library] Drools にチャレンジ

Drools とは

Drools は、 Charles Forgy's Rete algorithm をベースにした codehaus 謹製ルールエンジン。 JSR 94 にも準拠している。

Drools
http://drools.org/
Drools のサンプルコード
http://drools.org/Tutorials+and+Examples

Drools の実行環境構築

  1. Drools(drools-core-2.1.jar, drools-base-2.1.jar, drools-java-2.1.jar, drools-jsr94-2.1.jar, drools-io-2.1.jar, drools-smf-2.1.jar) をクラスパスに追加。
  2. その他必要なライブラリ (commons-logging-1.0.4.jar, jsr94-1.1.jar, jsr94-tck-1.1.jar, xercesImpl-2.6.2.jar, xml-apis-1.0b2.jar, antlr-2.7.5.jar, janino-2.3.8.jar) をクラスパスに追加

サンプルコード

Codelet.java (ここで使用している Rule は、Drools で公開されているサンプル)

package jp.in_vitro.codelets.drools;

import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

import javax.rules.ConfigurationException;
import javax.rules.InvalidRuleSessionException;
import javax.rules.ObjectFilter;
import javax.rules.RuleExecutionSetNotFoundException;
import javax.rules.RuleRuntime;
import javax.rules.RuleServiceProvider;
import javax.rules.RuleServiceProviderManager;
import javax.rules.RuleSessionCreateException;
import javax.rules.RuleSessionTypeUnsupportedException;
import javax.rules.StatelessRuleSession;
import javax.rules.admin.RuleAdministrator;
import javax.rules.admin.RuleExecutionSet;
import javax.rules.admin.RuleExecutionSetCreateException;
import javax.rules.admin.RuleExecutionSetRegisterException;

import org.drools.jsr94.rules.RuleServiceProviderImpl;

public class Codelet {

    public Codelet() throws ConfigurationException {
        super();

        this.initializeRuleEngine();

    }

    public static void main(final String[] args) throws Exception {

        Codelet me = new Codelet();
        me.execute();
    }

    public void execute() throws RuleExecutionSetCreateException,
            RuleExecutionSetRegisterException, ConfigurationException,
            RemoteException, IOException, RuleSessionTypeUnsupportedException,
            RuleSessionCreateException, RuleExecutionSetNotFoundException,
            InvalidRuleSessionException {

        String uri = "res://sample.drl";
        String resource = "/"
                + Codelet.class.getPackage().getName().replaceAll("\\.", "/")
                + "/sample.drl";

        InputStream is = null;
        try {
            is = Codelet.class.getResourceAsStream(resource);
            this.loadRuleExecutionSet(uri, is);
        } finally {
            if (is != null) {
                is.close();
            }
        }

        // Fibonacci は下記のサンプルをそのまま利用。
        // http://drools.org/Fibonacci+Example
        List facts = new ArrayList();
        facts.add(new Fibonacci(50));
        List conclusions = this.executeRuleExecutionSet(uri, facts, null);
        for (Object conclusion : conclusions) {
            System.out.println("" + conclusion);
        }
    }

    protected void initializeRuleEngine() throws ConfigurationException {
        RuleServiceProviderManager.registerRuleServiceProvider(
                RuleServiceProviderImpl.class.getName(),
                RuleServiceProviderImpl.class);
    }

    protected RuleServiceProvider prepareRuleServiceProvider()
            throws ConfigurationException {
        RuleServiceProvider provider = RuleServiceProviderManager
                .getRuleServiceProvider(RuleServiceProviderImpl.class.getName());

        return provider;
    }

    protected void loadRuleExecutionSet(final String uri, final InputStream is)
            throws ConfigurationException, RuleExecutionSetCreateException,
            RemoteException, IOException, RuleExecutionSetRegisterException {
        RuleServiceProvider provider = this.prepareRuleServiceProvider();
        RuleAdministrator administrator = provider.getRuleAdministrator();

        RuleExecutionSet ruleSet = administrator
                .getLocalRuleExecutionSetProvider(null).createRuleExecutionSet(
                        is, null);
        administrator.registerRuleExecutionSet(uri, ruleSet, null);
    }

    protected List executeRuleExecutionSet(final String uri, final List facts,
            final ObjectFilter filter) throws ConfigurationException,
            RuleSessionTypeUnsupportedException, RuleSessionCreateException,
            RuleExecutionSetNotFoundException, RemoteException,
            InvalidRuleSessionException {

        RuleServiceProvider provider = this.prepareRuleServiceProvider();
        RuleRuntime runtime = provider.getRuleRuntime();
        StatelessRuleSession session = null;
        List conclusions = null;
        try {
            session = (StatelessRuleSession) runtime.createRuleSession(uri,
                    null, RuleRuntime.STATELESS_SESSION_TYPE);

            conclusions = session.executeRules(facts, filter);
        } finally {
            if (session != null) {
                session.release();
            }
        }

        return conclusions;
    }
}
sample.drl (ここで使用している Rule は、Drools で公開されているサンプル)
<?xml version="1.0"?>
<rule-set name="fibonacci"
          xmlns="http://drools.org/rules"
          xmlns:java="http://drools.org/semantics/java"
          xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
          xs:schemaLocation="http://drools.org/rules rules.xsd
                             http://drools.org/semantics/java java.xsd">
  
  <java:import>jp.in_vitro.codelets.drools.Fibonacci</java:import>
  
  <rule name="Recurse" salience="10">
    <parameter identifier="f">
      <class>Fibonacci</class>
    </parameter>
    <java:condition>f.getValue() == -1</java:condition>
    <java:consequence>
      System.err.println( "recurse for " + f.getSequence() );
      drools.assertObject( new Fibonacci( f.getSequence() - 1 ) );
    </java:consequence>
  </rule>
  
  <rule name="Bootstrap 1" salience="20">
    <parameter identifier="f">
      <class>Fibonacci</class>
    </parameter>

    <java:condition>f.getSequence() == 1</java:condition>
    <java:condition>f.getValue() == -1</java:condition>
    <java:consequence>
      f.setValue( 1 );
      System.err.println( f.getSequence() + " == " + f.getValue() );
      drools.modifyObject( f );
    </java:consequence>
  </rule>
  
  <rule name="Bootstrap 2">
    <parameter identifier="f">
      <class>Fibonacci</class>
    </parameter>
    <java:condition>f.getSequence() == 2</java:condition>
    <java:condition>f.getValue() == -1</java:condition>
    <java:consequence>
      f.setValue( 1 );
      System.err.println( f.getSequence() + " == " + f.getValue() );
      drools.modifyObject( f );
    </java:consequence>
  </rule>
  
  <rule name="Calculate">
    <parameter identifier="f1">
      <java:class>Fibonacci</java:class>
    </parameter>
    <parameter identifier="f2">
      <java:class>Fibonacci</java:class>
    </parameter>
    <parameter identifier="f3">
      <java:class>Fibonacci</java:class>
    </parameter>
    <java:condition>f2.getSequence() == (f1.getSequence() + 1)</java:condition>
    <java:condition>f3.getSequence() == (f2.getSequence() + 1)</java:condition>
    <java:condition>f1.getValue() != -1</java:condition>
    <java:condition>f2.getValue() != -1</java:condition>
    <java:condition>f3.getValue() == -1</java:condition>
    <java:consequence>
      f3.setValue( f1.getValue() + f2.getValue() );
      System.err.println( f3.getSequence() + " == " + f3.getValue() );
      drools.modifyObject( f3 );
      drools.retractObject( f1 );
    </java:consequence>
  </rule>

</rule-set>

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 31, 2005

[Maven] Cruise Control と Maven2 を連携させたい

Maven2 で管理しているプロジェクトを Cruise Control と連携させたいのだが、残念なことに最新の Cruise Control 2.3.1 でも未だ Maven2 には対応していないみたい。

仕方がないので、Cruise Control 用の Maven2Builder Plugin を作ってみた。 作ってみたと言っても、Maven 1.x 用の Builder をちょっと変えただけなのだけれども。

またもやお約束ですが、この Plugin を利用して何らかの不利益を被ったとしても一切補償はできません。 SCM などできちんと管理されたソースコードで試行して品質をご自身で判断してからご利用ください。

ダウンロード

Cruise Control 用 Maven2Builder Plugin

使い方

  1. Cruise Control 2.3.1 の環境を準備する。
  2. 上から ZIP アーカイブをダウンロードする。
  3. 上のアーカイブから maven2builder-1.0.0.jar を取り出して $CC_HOME/lib にコピーする。
  4. $CC_HOME/cruisecontrol.sh を編集する。
    • JAVA_HOME を設定
    • CRUISE_PATH に $LIBDIR/maven2builder-1.0.0.jar を追加
  5. $CC_HOME/config.xmlを編集する。
    • plugin に jp.in_vitro.cruisecontrol_plugin.maven2builder.Maven2Builder を登録。name は "maven2"
    • builder に maven2 を指定
<cruisecontrol>
  <plugin name="maven2" 
          classname="jp.in_vitro.cruisecontrol_plugin.maven2builder.Maven2Builder"/>

  <project name="Gadgets">
    <listeners>
      <currentbuildstatuslistener file="/home/cruisecontrol/logs/Gadgets/status.txt" />
    </listeners>

    <bootstrappers>
      <svnbootstrapper localWorkingCopy="/home/cruisecontrol/projects/Gadgets" />
    </bootstrappers>

    <modificationset quietperiod="30" >
      <svn localWorkingCopy="/home/cruisecontrol/projects/Gadgets"/>
    </modificationset>

    <schedule interval="300" >
      <maven2 mavenscript="/opt/maven2/bin/mvn"
              pom="/home/cruisecontrol/projects/Gadgets/pom.xml"
              goal="test"/>
    </schedule>

    <log>
      <merge dir="/home/cruisecontrol/projects/Gadgets/target/surefire-reports"/>
    </log>

  </project>
</cruisecontrol>

トラブルシューティング

Q. Cruise Control の設定方法が分かりません。
A. Cruise Control のマニュアルをご覧ください。
Q. 動きません。
A. 管理者の必要最低限の機能しか実装していません。あきらめてください。

参考サイト

Cruise Control
http://cruisecontrol.sourceforge.net/
Cruise Control への Plugin 登録方法
http://cruisecontrol.sourceforge.net/main/plugins.html#registration

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 29, 2005

[Maven] Maven2 用 Jalopy Plugin

Maven2 から Jalopy(*1) を実行する Plugin を書いてみた。 居るとも思えないけれど、もし欲しい人がいたらどうぞ。 お約束ですが、この Plugin を利用して何らかの不利益を被ったとしても一切補償はできません。 SCM などできちんと管理されたソースコードで試行して品質をご自身で判断してからご利用ください。

*1 Java 用のコードフォーマッタ

ダウンロード

Maven2 用 Jalopy Plugin

使い方

  1. 上から ZIP アーカイブをダウンロードする。
  2. プロジェクトで使用しているリモートリポジトリ内の適切な位置に上記アーカイブを解凍する。
  3. pom.xml を編集してビルドライフサイクルを変更する。
<model>
  <build>
    </plugins>
      <plugin>
        <groupId>in-vitro</groupId>
        <artifactId>maven-jalopy-plugin</artifactId>
        <configuration>
          <convention>${basedir}/jalopy-rule.xml</convention>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>format</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</model>
    

トラブルシューティング

Q. ダウンロードできません
A. あきらめてください。管理者が配布を中止しているかもしれません。
Q. 上手く動作しません
A. あきらめてください。こんなアヤシゲな Plugin を無理に利用する必要はありません ;-)

参考サイト

Maven2 の Plugin 設定方法
http://maven.apache.org/maven2/guides/plugin/guide-java-plugin-development.html
Jalopy 公式サイト
http://jalopy.sourceforge.net/
Jalopy マニュアル
http://jalopy.sourceforge.net/manual.html

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 26, 2005

[JSR] JSR 168 Portlet Specification ダイジェスト

Portlet Specification をざっと眺めたときのメモ。

JSR 168 Portlet Specification

オリジナルの入手はこちら → JSR 168

PLT.1 Preface

JSR 168 に関連する仕様は、

  • Java 2 Platform, Enterprise Edigion, v1.3
  • Java Servlet, v2.3
  • JavaServer Pages, v1.2

PLT.2 Overview

Portal とは
情報システムのプレゼンテーション層に相当する機能で、一般的に personalization、single sign on、content aggregation などを提供する Web アプリケーションのこと。
Portlet とは
Java を利用して構築された Web Component。Portal から呼び出され、リクエストに応じて動的に画面生成を行う。Portlet Container に管理される。
Portlet Container とは
Portlet を管理し、Portlet の実行環境を提供するコンテナ。Portlet のライフサイクル管理、永続情報管理を行う。

PLT.3 Relationship with the Servlet Specification

Servlet と Portlet の違い。

  • Portlet は画面の一部のみを生成する。
  • Portlet は URL と直接的な関連を持たない
  • Web ブラウザは直接 Portlet を呼び出すことはできない。(必ず Portal 経由)
  • Portlet は Servlet よりリクエストハンドリングなどに関して細かく定義されている
  • Portlet の状態を表す Portlet Mode や Window State などが予め定義されている
  • Portlet は Potal ページ内に複数存在することができる
Portlet は Servlet にはない以下の機能がある。
  • Portlet 毎の設定情報、ユーザ毎の設定情報にアクセスできる
  • ユーザプロファイル情報にアクセスできる
  • HTML 内のリンクを Portal に適した形に書き換えることができる
  • Portlet Session にアクセスできる。スコープには application-wide, portlet private が選択できる。
Portlet は Servlet が提供している以下の機能を利用できない。
  • レスポンスの文字エンコーディングを指定できない
  • レスポンスの HTTP ヘッダを変更できない
  • リクエストの URL を参照できない
Portlet と Servlet の関係は、
  • Portlet は Servlet や JSP を呼び出すことができる。
  • Portlet Container は Servlet Container の拡張。

PLT.4 Concepts

Web ブラウザが Portal にアクセスすると、Portal は Portlet Container を呼び出す。 Portlet Container は、内部で管理している Portlet を呼び出す(必要な場合は複数の Portlet を呼び出す)。

┏━━┓ ┏━━┓ ┏━━━━━━━━━━┓
┃  ┃ ┃  ┃ ┃          ┃
┃  ┃ ┃  ┃ ┃┌────────┐┃
┃  ┃ ┃  ┃→┃│Portlet1│┃
┃  ┃ ┃  ┃ ┃└────────┘┃
┃  ┃ ┃  ┃ ┃┌────────┐┃
┃  ┃→┃  ┃→┃│Portlet2│┃
┃  ┃ ┃  ┃ ┃└────────┘┃
┃  ┃ ┃  ┃ ┃┌────────┐┃
┃  ┃ ┃  ┃→┃│Portlet3│┃
┃  ┃ ┃  ┃ ┃└────────┘┃
┃  ┃ ┃  ┃ ┃          ┃
┗━━┛ ┗━━┛ ┗━━━━━━━━━━┛
Brower  Portal   Portlet Container


      ↓ 生成された画面は・・・

 ┏━━━━━━━━━━┓
 ┃┌────────┐┃
 ┃│Title   │┃
 ┃├────────┤┃
 ┃│       1│┃
 ┃│Content │┃
 ┃│        │┃
 ┃└────────┘┃
 ┃┌───┐┌───┐┃
 ┃├───┤├───┤┃
 ┃│  2││  3│┃
 ┃└───┘└───┘┃
 ┗━━━━━━━━━━┛
  
Portlet はそれぞれ画面の一部分となる HTML を返すので、Web ブラウザには複数の子ウィンドウが開いたような画面が表示される。

PLT.5 The Portlet Interface

┌─────────────┐
│<<interface>>│
│   Portlet   │
├─────────────┤
├─────────────┤
└─────────────┘
      △
      |
┌──────────────┐
│ <<abstract>> │
│GenericPortlet│
├──────────────┤  ← Portlet はこのクラスを継承する。
├──────────────┤
└──────────────┘
  
  • Portlet のインスタンスは VM 毎に1つずつ(なので、分散環境でない場合は1つ)
  • Portlet のライフサイクルは Porlet#init → Porlet#processAction → Porlet#render → Porlet#destroy
  • Portlet Container は Servlet Container が Portlet アプリケーションの実行時に利用している ClassLoader と同一の ClassLoader を利用して Portlet をロードしなければならない
  • Portlet 実行時(Portlet#processAction) には PortletException, PortletSecurityException, UnavailableException が throw される可能性がある
    • PorletException・・・Porlet 実行中に何らかのエラーが発生した場合
    • PorletSecurityException・・・ユーザが Porlet の利用権限を持っていない場合
    • UnavailableException・・・Portlet が一時的もしくは永続的に利用不可能な場合
  • Portlet に渡されるリクエスト/レスポンスのインスタンスは Thread Safe ではない。

PLT.6 Portlet Config

  • Portlet Deployment Descriptor には title, short-title, keywords などの情報を記述できる
  • PortletConfig のインスタンスが Portlet Deployment Descriptor の情報を保持している

PLT.7 Portlet URLs

  • Portlet に指示を行うために、Portlet へのコマンドを含んだ URL を使用する。この URL を Porlet URL と呼ぶ。
  • Portlet URL を表す PortletURL インターフェースが定義されている。PortletURL#createActionURL, PorletURL#createRenderURL を使用して PortletURL のオブジェクトを生成できる。
  • 特定の Portlet Container 実装が内部情報を URL のクエリに含めている可能性があるので、Porlet を開発する際には HTTP の GET メソッドを使用した Form を利用すべきではない。
  • Porlet 毎の情報を PorletURL#setParameter を利用することで Portlet URL 内に組み込むことができる。
  • PortletURL#setSecure を使用することで、Portlet URL の転送時に SSL を使用しなければならないか否かを指定することができる。

PLT.8 Portlet Modes

  • Portlet Mode は Portlet が現在実行中の機能を表す。
  • 標準で定義されている Portlet Mode は、VIEW、EDIT、HELP。
    • VIEW・・・Portlet の現在状態を表示するモード。GenericPortlet#doView が対応する。
    • EDIT・・・Portlet の状態を変更する方法を提供するモード。GenericPortlet#doEdit が対応する。
    • HELP・・・Portlet に関するヘルプ情報を表示するモード。GenericPortlet#doHelp が対応する。
  • Deployment Descriptor の custom-portlet-mode を使用することでカスタムの Portlet Mode を定義できる。

PLT.9 Window States

  • Window State はレンダリングの際に Portlet がどの程度の情報を出力するかを表す。
  • 標準で定義されている Window State は、NORMAL、MAXIMIZED、MINIMIZED。
    • NORMAL・・・Portlet が他の Porlet とページをシェアしている状態を表す。
    • MAXIMIZED・・・Portlet がページ内のスペースを占有できる状態を表す。
    • MINIMIZED・・・Portlet は最小限の情報しか出力できない状態を表す。
  • Deployment Descriptor の custom-window-state を使用することでカスタムの Window State を定義できる。

PLT.10 Portlet Context

  • PortletContext のインスタンスは Portlet Application 毎に一つ(正確には VM 単位で)。
  • PortletContext は、初期化パラメータ、アトリビュート、リソースなどを管理する。
  • Portlet は PortletContext から RequestDispatcher を取得することで、Servlet や JSP を呼び出すことができる。
  • Portlet は ServletContext にもアクセスできる。この ServletContext は PortletContext と同一のデータを保持している。

PLT.11 Portlet Requests

PLT.12 Portlet Responses

PLT.13 Portal Context

PLT.14 Portlet Preferences

PLT.15 Sessions

PLT.16 Dispatching Requests to Servlets and JSPs

PLT.17 User Information

PLT.18 Caching

PLT.19 Portlet Applications

PLT.20 Security

PLT.21 Packaging and Deployment Descriptor

PLT.22 Portlet Tag Library

PLT.23 Technology Conpatibility Kit Requirements

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 25, 2005

[JSR] JSR 168 Portlet Specification について調査

関連サイト

JSR 168: Portlet Specification
http://www.jcp.org/en/jsr/detail?id=168
JSR 162: Portlet API
http://www.jcp.org/en/jsr/detail?id=162
JSR 167: Java Portlet Specification
http://www.jcp.org/en/jsr/detail?id=167
Apache Portals Project
http://portals.apache.org/
Apache Pluto
http://portals.apache.org/pluto/
Jetspeed 1
http://portals.apache.org/jetspeed-1/
Jetspeed 2
http://portals.apache.org/jetspeed-2/
JBoss Portal
http://www.jboss.com/products/jbossportal
※JSR 162 と JSR 167 が一つに統合されて JSR 168 となった(なので、JSR 162、JSR 167 は取り下げられた)。

Apache Pluto 1.0.1 インストールメモ

  1. Pluto をここからダウンロードする。面倒がないように Tomcat 入りのフルセットを落とす。
  2. Pluto をインストールする。適当な場所にアーカイブを解凍
  3. <PLUTO のインストール先>\bin\setenv.bat を作成。
    • 環境変数 JAVA_HOME を設定。ここで指定する JAVA_HOME は JDK5.0 のパス
    • 環境変数 PLUTO_HOME を設定。(ex. set PLUTO_HOME=c:\opt\pluto)
    • 環境変数 CATALINA_HOME を設定。PLUTO_HOME と同じパスが CATALINA_HOME になる。(ex. set CATALINA_HOME=%PLUTO_HOME%)
  4. Pluto を起動する。%PLUTO_HOME%\bin\startup.bat を実行
  5. Pluto の起動確認をする。http://localhost:8080/ にアクセス
  6. Pluto Test Driver を実行する。http://localhost:8080/pluto/portal にアクセス

[PLUTO の TOP 画面] [テストドライバの TOP 画面] [テストドライバ画面(1)] [テストドライバ画面(2)] [テストドライバ画面(3)] [PLUTO の管理画面]

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 24, 2005

[Maven] Maven2 Plugin の作り方

Maven2 Plugin 開発手順

  1. org.apache.maven.plugin.AbstractMojo を継承したクラスを作成する。
  2. pom.xml を作成する。

ディレクトリ構成

PROJECT_HOME
  ├src
  │ ├main
  │ │ └java
  │ │   └jp
  │ │    └in_vitro
  │ │       └hoge_plugin
  │ │          └HogeMojo.java ・・・ plugin 本体
  │ └test
  │   └java
  └pom.xml ・・・ plugin ビルド用 pom

pom.xml

<model>
  <modelVersion>4.0.0</modelVersion>
  <groupId>in-vitro</groupId>
  <artifactId>maven-hoge-plugin</artifactId>
  <packaging>maven-plugin</packaging>
  <version>1.0.0</version>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-tools-api</artifactId>
      <version>2.0</version>
    </dependency>
  </dependencies>
</model>

HogeMojo.java

package jp.in_vitro.hoge_plugin;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;

/**
 * @goal goalname
 * @description do something
 */
public class HogeMojo extends AbstractMojo {

    /**
     * プロジェクトのベースディレクトリ。
     *
     * @parameter expression="${basedir}"
     * @required
     */
    private File basedir;

    /**
     * {@link HogeMojo HogeMojo} を生成する。
     */
    public HogeMojo() {
        super();
    }

    /**
     * このプラグインを実行する。
     * このメソッドは Maven から呼び出される。
     * 
     * @throws MojoExecutionException プラグイン実行中にエラーが発生した場合。
     */
    public void execute() throws MojoExecutionException {
      // do something.
    }
}

参考サイト

Guide to Developing Java Plugins
http://maven.apache.org/maven2/guides/plugin/guide-java-plugin-development.html
Maven 標準 Plugin のソースコード
http://svn.apache.org/viewcvs.cgi/maven/components/trunk/maven-plugins/

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 23, 2005

[Maven] Build Task の自動化

プロジェクトの Build Task を自動化する方法を考えてみる。 Build Task は、プロジェクト毎に大同小異なのでベースは固まっていて且つカスタマイズ性が高い、というのがベスト。

Maven2 では、プロジェクトのライフサイクルが規定されている。 ライフサイクルは複数のフェーズから成っていて、それぞれのフェーズに任意の Goal を割り当てることができる。そのため、上記の要件をきちんと満たしてくれている。

デフォルト状態で規定されているライフサイクルは以下の通り。(maven-core-2.0.jar$META-INF/plexus/components.xml から抜粋)

<lifecycles>
  <lifecycle>
    <id>default</id>
    <phases>
      <phase>validate</phase>
      <phase>initialize</phase>
      <phase>generate-sources</phase>
      <phase>process-sources</phase>
      <phase>generate-resources</phase>
      <phase>process-resources</phase>
      <phase>compile</phase>
      <phase>process-classes</phase>
      <phase>generate-test-sources</phase>
      <phase>process-test-sources</phase>
      <phase>generate-test-resources</phase>
      <phase>process-test-resources</phase>
      <phase>test-compile</phase>
      <phase>test</phase>
      <phase>package</phase>
      <phase>integration-test</phase>
      <phase>verify</phase>
      <phase>install</phase>
      <phase>deploy</phase>
    </phases>
  </phases>
</lifecycle>
それぞれのフェーズの用途は Introduction to the Build Lifecycle で解説されている。 ここを適当にカスタマイズして Build Task を組み立てることができそう。

また、↓の様に独自のライフサイクルとフェーズを定義することもできる。

<lifecycle>
  <id>clean</id>
  <phases>
    <phase>pre-clean</phase>
    <phase>clean</phase>
    <phase>post-clean</phase>
  </phases>
  <default-phases>
    <clean>org.apache.maven.plugins:maven-clean-plugin:clean</clean>
  </default-phases>
</lifecycle>

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 22, 2005

[Maven] Maven2 まとめ

Maven2 が正式リリースされたので、まとめ。

関連サイト

公式サイト
http://maven.apache.org/maven2/
デフォルトのリモートリポジトリ
http://repo1.maven.org/maven2
プラグイン一覧
http://maven.apache.org/maven2/plugins/index.html

インストール

  1. ここから Maven2 をダウンロードする
  2. アーカイブを適当な位置(ex. /opt/maven-2.0/)に解凍
  3. 環境変数 MAVEN_HOME を設定(ex. export MAVEN_HOME=/opt/maven-2.0)
  4. 環境変数 PATH を設定(ex. export PATH=$MAVEN_HOME/bin:$PATH)
  5. 起動確認 "mvn --version"
$ tar zxvf ./maven-2.0-bin.tar.gz
$ export MAVEN_HOME=/opt/maven-2.0
$ export PATH=$MAVEN_HOME/bin:$PATH
$ mvn --version
Maven version: 2.0

※公式なインストール方法(?)はこちら→Installation Instructions

プロジェクトの作成

  1. groupId, artifactId を考える
  2. archetype プラグインを実行(ex. mvn:create -DgroupId=in-vitro -DartifactId=sample)
  3. 生成されたプロジェクトを確認。カレントディレクトリ内に指定した artifactId と同名のプロジェクトディレクトリが生成されている。

archetype プラグイン実行時に指定可能なパラメータはこちら → archetype:create

※artifactId はプロジェクト成果物となるモジュール(?)のID。groupId は artifactId をグルーピングする際のID。

$ mvn archetype:create -DgroupId=in-vitro -DartifactId=sample
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] artifact org.apache.maven.plugins:maven-archetype-plugin: checking for up
dates from central
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-archet
ype-plugin/1.0-alpha-3/maven-archetype-plugin-1.0-alpha-3.pom
1K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-archet
ype-plugin/1.0-alpha-3/maven-archetype-plugin-1.0-alpha-3.jar
6K downloaded
[INFO] -------------------------------------------------------------------------
---
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:create] (aggregator-style)
[INFO] -------------------------------------------------------------------------
---
Downloading: http://repo1.maven.org/maven2/org/apache/maven/maven-archetype-core
/1.0-alpha-3/maven-archetype-core-1.0-alpha-3.pom
1K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/maven-archetype/1.0-
alpha-3/maven-archetype-1.0-alpha-3.pom
661b downloaded

  ...snip...

[INFO] -------------------------------------------------------------------------
---
[INFO] Using following parameters for creating Archetype: maven-archetype-quicks
tart:RELEASE
[INFO] -------------------------------------------------------------------------
---
[INFO] Parameter: groupId, Value: in-vitro
[INFO] Parameter: outputDirectory, Value: C:\_workspace\sample
[INFO] Parameter: packageName, Value: in-vitro
[INFO] Parameter: package, Value: in-vitro
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: artifactId, Value: sample
[INFO] ResourceManager : found archetype-resources/pom.xml with loader org.codeh
aus.plexus.velocity.ContextClassLoaderResourceLoader
[INFO] ********************* End of debug info from resources from generated POM
 ***********************
[INFO] ResourceManager : found archetype-resources/src/main/java/App.java with l
oader org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader
[INFO] ResourceManager : found archetype-resources/src/test/java/AppTest.java wi
th loader org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader
[INFO] Archetype created in dir: C:\_workspace\sample
[INFO] -------------------------------------------------------------------------
---
[INFO] BUILD SUCCESSFUL
[INFO] -------------------------------------------------------------------------
---
[INFO] Total time: 1 minute 35 seconds
[INFO] Finished at: Sat Oct 29 10:40:08 JST 2005
[INFO] Final Memory: 4M/7M
[INFO] -------------------------------------------------------------------------
---

$

pom.xml を眺めてみる

archetype プラグインが生成したプロジェクトディレクトリ(上の例では in-vitro )の直下に pom.xml ファイルが生成されている。 pom.xml はプロジェクトに関する各種設定を記述するファイルで Project Descriptor と呼ばれる。

pom.xml のフォーマットはこちら → Project Descriptor

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>in-vitro</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

プロジェクトをビルドしてみる

Maven2 ではビルドライフサイクルという概念が定義されている。 Maven2 実行時に規定されたビルドライフサイクルを指定することで、予め定義された順序でプラグインが逐次実行される。 ビルドライフサイクルには compile, package, install, deploy などが規定されている。

プロジェクトのビルドする場合、"mvn compile" といった様に Maven2 にビルドライフサイクルを指定する。

ビルドライフサイクルに関する詳細はこちら → Introduction to the Build Lifecycle

$mvn compile
[INFO] Scanning for projects...
[INFO] -------------------------------------------------------------------------
---
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [compile]
[INFO] -------------------------------------------------------------------------
---
[WARNING] POM for: 'commons-io:commons-io:pom:1.0' does not appear to be valid.
Its will be ignored for artifact resolution.

Reason: Failed to validate POM


[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
Compiling 1 source file to /home/in-vitro/projects/sample/target/classes
[INFO] -------------------------------------------------------------------------
---
[ERROR] BUILD FAILURE
[INFO] -------------------------------------------------------------------------
---
[INFO] Compilation failure

/home/in-vitro/projects/sample/src/main/java/in-vitro/App.java:[1,10] ';' があり
ません。


[INFO] -------------------------------------------------------------------------
---
[INFO] For more information, run Maven with the -e switch
[INFO] -------------------------------------------------------------------------
---
[INFO] Total time: 2 seconds
[INFO] Finished at: Sat Oct 29 11:00:58 JST 2005
[INFO] Final Memory: 3M/5M
[INFO] -------------------------------------------------------------------------
---

$

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 17, 2005

[Mustang] Java Compiler API にチャレンジ

Java Compiler API とは

クラスライブラリからソースコードをコンパイルしてバイトコード化できる API。 仕様は JCP で JSR199 として策定中。

本当は Tiger で JDK に導入されるはずだったのだが、いつの間にやら Mustang に延期されていた。 現在の Mustang の snapshot には動作するコードが入っているので、Mustang でのお披露目は大丈夫そう。 Code Generator のランタイム実行、Rule Engine の高速化などなど色々な用途がありそうなので正式リリースが待ち遠しい。

JSR199 Java Compiler API
http://jcp.org/en/jsr/detail?id=199

Java Compiler API の実行環境構築

  1. Mustang をインストールすれば万事 OK

サンプルコード

↓は以下の処理を行うサンプルコード。

  1. ハードコーディングされているソースコードをコンパイル
  2. コンパイルで生成されたバイトコードをオンメモリのまま ClassLoader でローディング
  3. ClassLoader から Class を取得して main メソッドを実行
たったこれだけなのに、結構なコーディングが必要だった。 まだ Mustang が開発中だから仕方がないか。 今後に期待!!

Codelet.java

package jp.in_vitro.codelets.mustang.compilerapi;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.tools.DiagnosticMessage;
import javax.tools.JavaCompilerTool;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaCompilerTool.CompilationTask;

public class Codelet {
    public Codelet() {
        super();
    }

    public static void main(final String[] args) {
        Codelet me = new Codelet();
        me.execute();
    }

    protected void execute() {
        this.execute01();
        this.execute02();
        this.execute03();
    }

    protected void execute01() {
        // HelloWorld
        JavaCompilerTool compiler = this.prepareJavaCompilerTool();
        JavaFileManagerImpl fileManager = this
                .prepareJavaFileManagerImpl(compiler);

        String sourceCode = "public class HelloWorld {" + 
          "public static void main(String[] args){" + 
          "System.out.println(\"Hello, World!\");}}";
        String className = "HelloWorld";
        JavaSourceFileObject sourceObject = new JavaSourceFileObject(className,
                sourceCode);
        this.compile(compiler, fileManager, sourceObject);
        this.executeMain(fileManager, "HelloWorld", new String[0]);

    }

    protected void execute02() {
        // 複数クラスのコンパイル
        JavaCompilerTool compiler = this.prepareJavaCompilerTool();
        JavaFileManagerImpl fileManager = this
                .prepareJavaFileManagerImpl(compiler);

        // Main
        String mainSourceCode = "public class Main {" + 
          "public static void main(String[] args){" + 
          "Sub sub = new Sub(); sub.execute();}}";
        String mainClassName = "Main";
        JavaSourceFileObject mainSourceObject = new JavaSourceFileObject(
                mainClassName, mainSourceCode);

        // Sub
        String subSourceCode = "public class Sub {" + 
          "public void execute(){" + 
          "System.out.println(\"Sub was executed!!\");}}";
        String subClassName = "Sub";
        JavaSourceFileObject subSourceObject = new JavaSourceFileObject(
                subClassName, subSourceCode);

        this.compile(compiler, fileManager, mainSourceObject, subSourceObject);
        this.executeMain(fileManager, "Main", new String[0]);
    }

    protected void execute03() {
        // コンパイルエラー
        JavaCompilerTool compiler = this.prepareJavaCompilerTool();
        JavaFileManagerImpl fileManager = this
                .prepareJavaFileManagerImpl(compiler);

        String sourceCode = "public class Uncompilable {" + 
          "public static void main(String[] args){" + 
          "executeAbEsseMethod();}}";
        String className = "Uncompilable";
        JavaSourceFileObject sourceObject = new JavaSourceFileObject(className,
                sourceCode);
        this.compile(compiler, fileManager, sourceObject);
        this.executeMain(fileManager, "Uncompilable", new String[0]);
    }

    protected void compile(final JavaCompilerTool compiler,
            final JavaFileManagerImpl fileManager,
            final JavaSourceFileObject... sourceObjects) {

        CompilationTask task = compiler.run(null,
                (JavaFileObject[]) sourceObjects);
        if (task.getResult()) {
            System.out.println();
            System.out
                    .println("************************************************");
            System.out.println("*  Compilation souce(s) completed!!");
            System.out
                    .println("************************************************");
            for (JavaSourceFileObject sourceObject : sourceObjects) {
                System.out.println("" + sourceObject.getName());
            }
        } else {
            System.out.println();
            System.out
                    .println("************************************************");
            System.out.println("*  Compilation souce(s) failed!!");
            System.out
                    .println("************************************************");
            for (DiagnosticMessage message : task.getDiagnostics()) {
                System.out.println("" + message);
            }
            throw new IllegalStateException();
        }
    }

    protected void executeMain(final JavaFileManagerImpl fileManager,
            final String className, final String[] args) {
        System.out.println();
        System.out.println("************************************************");
        System.out.println("*  Execute " + className);
        System.out.println("************************************************");

        ClassLoader loader = this.prepareClassLoader(fileManager);
        try {
            Class testClass = loader.loadClass(className);
            Method mainMethod = testClass.getMethod("main",
                    new Class[] { String[].class });
            mainMethod.invoke(null, new Object[] { args });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected JavaCompilerTool prepareJavaCompilerTool() {
        JavaCompilerTool compiler = ToolProvider.defaultJavaCompiler();
        compiler.setExtendedOption("-Xlint:all");
        return compiler;
    }

    protected JavaFileManagerImpl prepareJavaFileManagerImpl(
            final JavaCompilerTool compiler) {
        JavaFileManagerImpl fileManager = new JavaFileManagerImpl(compiler
                .getStandardFileManager());
        compiler.setFileManager(fileManager);
        return fileManager;
    }

    protected ClassLoader prepareClassLoader(
            final JavaFileManagerImpl fileManager) {
        ClassLoaderImpl loader = new ClassLoaderImpl();
        for (String className : fileManager.getClassNames()) {
            loader.addClass(className, fileManager.getClass(className)
                    .getCode());
        }
        return loader;
    }
}

AbstractJavaFileObject.java

package jp.in_vitro.codelets.mustang.compilerapi;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.CharBuffer;

import javax.tools.JavaFileObject;

public abstract class AbstractJavaFileObject implements JavaFileObject {
    private Kind kind;
    private String name;

    public AbstractJavaFileObject(final String name, final Kind kind) {
        super();
        this.name = name;
        this.kind = kind;
    }

    public Kind getKind() {
        return this.kind;
    }

    public boolean delete() {
        return false;
    }

    public String getNameWithoutExtension() {
        return this.name;
    }

    public String getName() {
        return this.name;
    }

    public String getPath() {
        return this.name;
    }

    public long lastModified() {
        return 0L;
    }

    public long lengthInBytes() {
        return -1L;
    }

    public boolean matches(final String simpleName, final Kind kind) {
        return this.kind.equals(kind) && name.equals(simpleName);
    }

    public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
        throw new UnsupportedOperationException();
    }

    public InputStream openInputStream() {
        throw new UnsupportedOperationException();
    }

    public OutputStream openOutputStream() {
        throw new UnsupportedOperationException();
    }

    public Reader openReader() {
        throw new UnsupportedOperationException();
    }

    public Writer openWriter() {
        throw new UnsupportedOperationException();
    }
}

JavaSourceFileObject.java

package jp.in_vitro.codelets.mustang.compilerapi;

import java.io.Reader;
import java.io.StringReader;
import java.nio.CharBuffer;

public class JavaSourceFileObject extends AbstractJavaFileObject {
    private String code;

    public JavaSourceFileObject(final String name, final String code) {
        super(name, Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
        return CharBuffer.wrap(code);
    }

    @Override
    public Reader openReader() {
        return new StringReader(code);
    }

    @Override
    public String getName() {
        return getNameWithoutExtension() + ".java";
    }
}

JavaClassFileObject.java

package jp.in_vitro.codelets.mustang.compilerapi;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class JavaClassFileObject extends AbstractJavaFileObject {
    private byte[] code;

    public JavaClassFileObject(final String name) {
        super(name, Kind.CLASS);
    }

    @Override
    public OutputStream openOutputStream() {
        return new ClassOutputStream();
    }

    public class ClassOutputStream extends ByteArrayOutputStream {
        public void close() throws IOException {
            super.close();
            JavaClassFileObject.this.code = super.toByteArray();
        }
    }

    public byte[] getCode() {
        return code;
    }
}

JavaFileManagerImpl.java

package jp.in_vitro.codelets.mustang.compilerapi;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;

public class JavaFileManagerImpl implements JavaFileManager {
    private Map classes = new HashMap();
    protected final JavaFileManager parentFileManager;

    public JavaFileManagerImpl(final JavaFileManager parentFileManager) {
        super();
        this.parentFileManager = parentFileManager;
    }

    public JavaClassFileObject getClass(final String name) {
        return this.classes.get(name);
    }

    public Set getClassNames() {
        return Collections.unmodifiableSet(this.classes.keySet());
    }

    public JavaFileObject getFileForOutput(final String name, final Kind kind,
            final JavaFileObject originatingSource) {
        if (originatingSource instanceof JavaSourceFileObject) {
            JavaClassFileObject classObject = new JavaClassFileObject(name);
            this.classes.put(name, classObject);
            return classObject;
        } else {
            throw new UnsupportedOperationException();
        }
    }

    public void close() throws IOException {
        this.parentFileManager.close();
    }

    public void flush() throws IOException {
        this.parentFileManager.flush();
    }

    public void setLocation(final String location, final String path) {
        this.parentFileManager.setLocation(location, path);
    }

    public Iterable list(final String packageName,
            final Set kinds) throws IOException {
        return this.parentFileManager.list(packageName, kinds);
    }

    public JavaFileObject getFileForInput(final String name) {
        throw new UnsupportedOperationException();
    }

    public JavaFileObject getFileForOutput(final String filename,
            final String location, final String pkg) throws IOException {
        throw new UnsupportedOperationException();
    }
}

ClassLoaderImpl.java

package jp.in_vitro.codelets.mustang.compilerapi;

import java.util.HashMap;
import java.util.Map;

public class ClassLoaderImpl extends ClassLoader {
    private Map classes = new HashMap();

    public ClassLoaderImpl() {
        super();
    }

    public ClassLoaderImpl(final ClassLoader parent) {
        super(parent);
    }

    public void addClass(final String name, final byte[] bytecode) {
        this.classes.put(name, bytecode);
    }

    public void addClasses(final Map classes) {
        this.classes.putAll(classes);
    }

    @Override
    public Class< ? > loadClass(final String name)
            throws ClassNotFoundException {
        try {
            return super.loadClass(name);
        } catch (ClassNotFoundException e) {
            byte[] classData = classes.get(name);
            return defineClass(name, classData, 0, classData.length);
        }
    }
}

サンプルの実行結果

↑の Codelet#main を実行した結果は↓

************************************************
*  Compilation souce(s) completed!!
************************************************
HelloWorld.java

************************************************
*  Execute HelloWorld
************************************************
Hello, World!

************************************************
*  Compilation souce(s) completed!!
************************************************
Main.java
Sub.java

************************************************
*  Execute Main
************************************************
Sub was executed!!

************************************************
*  Compilation souce(s) failed!!
************************************************
Uncompilable:1: シンボルを見つけられません。
シンボル: メソッド executeAbEsseMethod()
場所    : Uncompilable の クラス
Exception in thread "main" java.lang.IllegalStateException
	at jp.in_vitro.codelets.mustang.compilerapi.Codelet.compile(Codelet.java:113)
	at jp.in_vitro.codelets.mustang.compilerapi.Codelet.execute03(Codelet.java:81)
	at jp.in_vitro.codelets.mustang.compilerapi.Codelet.execute(Codelet.java:27)
	at jp.in_vitro.codelets.mustang.compilerapi.Codelet.main(Codelet.java:20)

Posted in Mustang | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 16, 2005

[Mustang] Mustang メモ

そろそろ Mustang も視野にいれておかないと、ということで一通りメモ。

Mustang
http://mustang.dev.java.net/
JDK 6 Documentation
http://download.java.net/jdk6/docs/
Java SE 6, Platform Name and Version Numbers
http://download.java.net/jdk6/docs/relnotes/version-6.html
JSR270 JavaTM SE 6 ("Mustang")
http://www.jcp.org/en/jsr/detail?id=270
Mustang が関連する JSR はこちら↓。
JSR105 XML Digital Signature
http://jcp.org/en/jsr/detail?id=105
JSR199 Java Compiler API
http://jcp.org/en/jsr/detail?id=199
JSR202 JavaTM Class File Specification Update
http://jcp.org/en/jsr/detail?id=202
JSR221 JDBC 4.0
http://jcp.org/en/jsr/detail?id=221
JSR222 JAXB 2.0
http://jcp.org/en/jsr/detail?id=222
JSR223 Scripting for the JavaTM Platform
http://jcp.org/en/jsr/detail?id=223
JSR224 JAX-RPC 2.0
http://jcp.org/en/jsr/detail?id=224
JSR260 Javadoc Tag Update
http://jcp.org/en/jsr/detail?id=260
JSR268 Java Smart Card I/O API
http://jcp.org/en/jsr/detail?id=268
JSR269 Pluggable Annotation Processing API
http://jcp.org/en/jsr/detail?id=269

Posted in Mustang | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 14, 2005

[JSR] JSR 250 Common Annotations for the Java Platform ダイジェスト

Common Annotations for the Java Platform の仕様をざっと眺めたときのメモ。

JSR 250 Common Annotations for the Java Platform

オリジナルの入手はこちら → JSR 250

General Guidelines for Inheritance of Annotations

annotation が付加されたメソッドがサブクラスでオーバーライドされた場合、 どのように扱われるのかが曖昧。そのため、そのような場合におけるガイドラインを 以下の様に定義する。

  • クラスレベル annotation は自分自身のメンバー(メソッド、フィールド)のみを対象とする。
  • クラスレベル annotation よりメンバーレベル annotation の方が優先される。
  • インターフェースは実装されているクラス(メンバーを含む)に影響を与えない。
  • オーバーライドもしくは隠蔽されていないメンバーは子クラスにおいても親クラスの annotation を引き継ぐ。
  • オーバーライドもしくは隠蔽されているメンバーは子クラスにおいて親クラスの annotation の影響を受けない。

javax.annotation.Generated

自動生成されたコードを表す。 自動生成ツールの名称を必ず指定しなければならない。 自動生成された時刻を記述可能。時刻は ISO 8601 のフォーマットに従わなければならない。 ターゲットは ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE。

javax.annotation.Resource

DataSource などを自動でクラスにインジェクションするために利用される。 JNDI 名を指定することで、コンテナが JNDI から適切なリソースを取得しフィールドインジェクションもしくはメソッドインジェクションで対象オブジェクトに引き渡す。 ターゲットは TYPE, METHOD, Field。

javax.annotation.Resources

複数のリソースを必要とする場合、Resources を利用して複数の Resource をまとめる。 同一 annotation の複数回指定が認められていないため。 ターゲットは TYPE。

javax.annotation.PostConstruct

インジェクション終了直後に実行されるメソッドを表す。 オブジェクト生成→インジェクション→PostConstruct指定されたメソッド実行、というライフサイクルになる。 ターゲットは METHOD。 この annotation を付加されるメソッドには以下の制限がある。

  • パラメータは指定できない(但し、EJB interceptor における InvocationContext のみ可能)
  • 戻り値は void のみ。
  • チェック例外は throw できない。
  • アクセス識別子は public, protected, package private, private を指定可能。
  • static にできない。
  • final を指定可能。
  • 非チェック例外を throw した場合は、そのオブジェクトを利用してはいけない。

javax.annotation.PreDestroy

コンテナがオブジェクトを破棄する際に実行されるメソッドを表す。 ターゲットは METHOD。 この annotation を付加されるメソッドには以下の制限がある。

  • パラメータは指定できない(但し、EJB interceptor における InvocationContext のみ可能)
  • 戻り値は void のみ。
  • チェック例外は throw できない。
  • アクセス識別子は public, protected, package private, private を指定可能。
  • static にできない。
  • final を指定可能。
  • 非チェック例外を throw した場合、その例外は無視される。

javax.annotation.security.RunAs

クラスのロールを表す。 Java EE コンテナでクラスが実行される際、RunAs でクラスのロールを割り当てることができる。 ターゲットは TYPE。

javax.annotation.security.RolesAllowed

クラス、メソッドの実行権限を持つロールを指定する。 ターゲットは TYPE, METHOD。

javax.annotation.security.PermitAll

全てのロールが実行権限を持つことを表す。 PermitAll が指定されたクラス、メソッドは権限に関して未チェックで実行される。 ターゲットは TYPE, METHOD。

javax.annotation.security.DenyAll

全てのロールが実行権限を持たないことを表す。 DenyAll が指定されたクラス、メソッドは Java EE コンテナ上では実行できない。 ターゲットは METHOD。

PermitAll, DenyAll and RolesAllowed interactions

  • PermitAll, DenyAll, RolesAllowed は特定のクラスもしくはメソッドに同時に指定することはできない。
  • DenyAll がクラスレベルで指定されている場合、メソッドに PermitAll, RolesAllowed が指定されると PermitAll, RolesAllowed が優先される。
  • RolesAllowed がクラスレベルで指定されている場合、メソッドに DenyAll, PermitAll が指定されると DenyAll, PermitAll が優先される。

謎) DenyAll のターゲットは METHOD のみなのに、ここではクラスレベルで指定できると書かれている。どちらが正しいの??

javax.annotation.security.DeclareRoles

テスト等で使用するためのロールを定義する。 ターゲットは TYPE。

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 09, 2005

[Library] JCIFS の概要

JCIFS のクラス図

JCIFS 1.2.6 の「イイカゲン」なクラス図を作ってみた。

[JCIFS 1.2.6 のクラス図]

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 08, 2005

[Library] JCIFS にチャレンジ

JCIFS とは

JCIFS は CIFS/SMB の Java 用ライブラリ。 要するに Java から Windows のファイルシステムにアクセスできる。

JCIFS
http://jcifs.samba.org/

JCIFS の実行環境構築

  1. JCIFS(jcifs-1.2.6.jar) をクラスパスに追加

サンプルコード

package jp.in_vitro.codelets.jcifs;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.Properties;

import jcifs.Config;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;

public class Codelet {

    public Codelet() {
        super();
    }

    public static void main(final String[] args) throws Exception {
        Codelet me = new Codelet();
        me.initializeJcifs();
        me.printFileList("smb://myclient/c$/");
        me.printFile("smb://myclient/SharedDocs/tmp.txt");
    }

    protected void initializeJcifs() {
        Config.setProperties(this.prepareSystemConfiguration());
    }

    protected Properties prepareSystemConfiguration() {

        Properties props = new Properties();

        props.setProperty("jcifs.netbios.wins", "192.168.1.1");
        props.setProperty("jcifs.smb.client.username", "myname");
        props.setProperty("jcifs.smb.client.password", "mypassword");

        return props;
    }

    public void printFileList(final String target)
            throws MalformedURLException, SmbException {

        SmbFile dir = new SmbFile(target);
        if (!dir.isDirectory()) {
            return;
        }

        SmbFile[] children = dir.listFiles();
        for (SmbFile child : children) {
            if (child.isDirectory()) {
                System.out.print("[DIR]");
            }
            System.out.print(" ");
            System.out.print("" + child.getCanonicalPath());
            System.out.print(" ");
            System.out.print("" + new Date(child.getDate()));
            System.out.println();
        }
    }

    public void printFile(final String target) throws IOException {

        SmbFileInputStream in = new SmbFileInputStream(target);
        int ch = 0;
        while ((ch = in.read()) >= 0) {
            System.out.print("" + (char) ch);
        }
    }
}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 06, 2005

[Book] Domain Driven Design

書籍情報


Domain Driven Design

レビュー

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 03, 2005

[Book] Object Design

書籍情報


Object Design

レビュー

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 28, 2005

[Library] コンテンツ移動のお知らせ

http://www.in-vitro.jp/blog/index.cgi/Library/20050928_01.html はこちらに移動しました。
Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

[Derby] Derby の実行速度

Derby の INSERT 速度を試してみた。 時間がなかったのでかなりいい加減。 非常に単純な INSERT 文を 100 万回繰り返してみた。

結果


embedded モード server モード
INSERT 1000000回
コネクション毎に 1000000 件ずつ 1 回繰り返し
45406msec (≒45秒) 320594msec (≒5分)
INSERT 1000000回
コネクション毎に 1000 件ずつ 1000 回繰り返し
51797msec (≒52秒) 321812msec (≒5分)
INSERT 1000000回
コネクション毎に 1 件ずつ 1000000 回繰り返し
798422msec (≒13分) 計測不能(何故か Exception で落ちる)

環境

OS
Windows XP Professional
CPU
Pentium4 2.4GHz
Memory
1GByte

コード(部分抜粋)

    protected void insertRecordMassively1() throws SQLException {

        // 1 回のコネクションで 1000 件の INSERT を 1000 回繰り返す。
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            Connection connection = this.getConnection();
            try {
                PreparedStatement statement = connection
                        .prepareStatement("INSERT INTO sample VALUES (?,?)");

                for (int j = 0; j < 1000; j++) {
                    int field01 = (int) ((Math.random() * 100000) % 10000);
                    String field02 = "01:" + field01;
                    statement.setInt(1, field01);
                    statement.setString(2, field02);
                    statement.executeUpdate();
                }

                connection.commit();
                connection.close();

            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        }
        long end = System.currentTimeMillis();

        System.out.println("INSERT * 1000 * 1000 : " + (end - start) + "msec");
    }

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 26, 2005

[Library] コンテンツ移動のお知らせ

http://www.in-vitro.jp/blog/index.cgi/Library/20050926_01.html はこちらに移動しました。
Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

[Derby] Derby を server モードで起動

先日は Derby を embedded モードで起動したので、今回は server モードを試してみた。 server モードの場合も embedded モードとほとんど同一のコードで起動できた。 意外と簡単。 クライアント側も Driver と URL を変更したら何事も無く接続できた。

Derby の実行環境構築

Derby を Server モードで起動する場合、embedded モードで利用したもの + α の jar が必要になる。

  1. Derby(derby.jar、derbynet.jar、derbyclient.jar) をクラスパスに追加

サンプルコード

package jp.in_vitro.codelets.derby;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import org.apache.derby.drda.NetworkServerControl;

public class Codelet3 {

    public Codelet3() {
        super();
    }

    public static void main(final String[] args) throws Exception {
        Codelet3 me = new Codelet3();
        me.execute();
    }

    protected void execute() throws Exception {

        // Derby の起動。
        DerbyServer server = new DerbyServer();
        server.start();
        while (!server.isInitialized()) {
            Thread.sleep(1000);
        }

        // ネットワーク(と言っても loopback)経由で Derby に接続。
        DerbyClient client = new DerbyClient();
        client.initializeClient();
        client.execute();

        // Derby の終了。
        server.stop();
    }

    public static class DerbyClient {
        private static final String DRIVER = "org.apache.derby.jdbc.ClientDriver";
        private static final String PROTOCOL = "jdbc:derby://localhost:1527/";

        public DerbyClient() throws ClassNotFoundException {
            super();
            this.initializeClient();
        }

        public void execute() throws SQLException {

            Connection connection = null;
            try {
                connection = this.getConnection();
                Statement statement = connection.createStatement();
                ResultSet rs = statement
                        .executeQuery("SELECT * FROM sys.systables");
                while (rs.next()) {
                    System.out.println("" + rs.getString(1));
                }

                rs.close();
                connection.commit();
                connection.close();

            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        }

        protected void initializeClient() throws ClassNotFoundException {
            Class.forName(DRIVER);
        }

        protected Connection getConnection() throws SQLException {

            Connection connection = null;
            Properties props = new Properties();
            props.put("user", "me");
            props.put("password", "password");

            connection = DriverManager.getConnection(PROTOCOL
                    + "derbyDB;create=true", props);
            connection.setAutoCommit(false);

            return connection;
        }
    }

    public static class DerbyServer implements Runnable {
        private static final String DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
        private static final String PROTOCOL = "jdbc:derby:";
        private Thread thread;
        private boolean initialized;

        public DerbyServer() {
            super();
        }

        public void start() {
            if (this.thread == null) {
                this.thread = new Thread(this);
                this.thread.start();
            }
        }

        public void stop() {
            if (this.thread != null) {
                this.thread = null;
            }
        }

        public void run() {
            try {
                this.initializeDBMS();
                while (this.thread != null) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
                this.destroyDBMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public boolean isInitialized() {
            return this.initialized;
        }

        protected void initializeDBMS() throws Exception {

            System.setProperty("derby.drda.startNetworkServer", "true");
            Class.forName(DRIVER).newInstance();

            NetworkServerControl server = new NetworkServerControl();
            server.ping();

            this.initialized = true;
        }

        protected void destroyDBMS() throws SQLException {

            this.initialized = false;

            Connection connection = null;
            try {
                connection = DriverManager.getConnection(PROTOCOL
                        + ";shutdown=true");
                connection.commit();

            } catch (SQLException e) {
                // Derby が正常終了すると SQLException が発行される。
                System.out.println("" + e.getLocalizedMessage() + " : "
                        + e.getErrorCode());
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        }
    }
}

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 25, 2005

[Library] JavaSVN の概要

JavaSVN のクラス図

JavaSVN 0.9.3 の「イイカゲン」なクラス図を作ってみた。

[JavaSVN 0.9.3 のクラス図]

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 23, 2005

[Library] JavaSVN にチャレンジ

JavaSVN とは

Java から Subversion にアクセスできるライブラリ。 Subversion のクライアントを Pure Java で実装しているツワモノ。 お馴染み Eclipse 用 Subversion Plugin の Subclipse でも内部で利用されている。

JavaSVN
http://tmate.org/svn/
JavaSVN サンプルコード
http://tmate.org/svn/kb/examples/index.php
類似のツールに JSVN があるが、JSVN はネイティブの svn コマンドを呼び出すだけなので使いづらい。

JavaSVN の実行環境構築

  1. JavaSVN (ganymed.jar, javasvn.jar, javasvn-cli.jar, javasvn-javahl.jar) をクラスパスに追加する

サンプルコード

package jp.in_vitro.codelets.javasvn;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

public class Codelet {

    public Codelet() {
        super();
    }

    public static void main(final String[] args) throws SVNException {

        String url = "http://example.com/repos/";
        String username = "myname";
        String password = "mypassword";

        Codelet me = new Codelet();
        me.initializeJavaSVN();
        SVNRepository repository = me.prepareSVNRepository(url, username,
                password);
        me.printInfo(repository, "projects/");
        me.printInfo(repository, "projects/pom.xml");

        repository.closeSession();
    }

    protected void initializeJavaSVN() {
        DAVRepositoryFactory.setup();
        SVNRepositoryFactoryImpl.setup();
    }

    protected void printInfo(final SVNRepository repository, final String path)
            throws SVNException {

        SVNNodeKind nodeKind = repository.checkPath(path, -1);
        if (nodeKind == SVNNodeKind.NONE) {
            System.out.println("NONE");
        } else if (nodeKind == SVNNodeKind.UNKNOWN) {
            System.out.println("UNKNOWN");
        } else if (nodeKind == SVNNodeKind.DIR) {
            Map properties = new HashMap();
            List children = new ArrayList();
            repository.getDir(path, -1, properties, children);

            System.out.println("*** properties ***");
            for (Object key : properties.keySet()) {
                System.out.println("" + key + " - " + properties.get(key));
            }
            System.out.println("*** children ***");
            for (Object child : children) {
                System.out.println("" + child);
            }

        } else if (nodeKind == SVNNodeKind.FILE) {
            Map properties = new HashMap();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            repository.getFile(path, -1, properties, baos);

            System.out.println("*** properties ***");
            for (Object key : properties.keySet()) {
                System.out.println("" + key + " - " + properties.get(key));
            }
        }

    }

    protected SVNRepository prepareSVNRepository(final String url,
            final String username, final String password) throws SVNException {

        SVNRepository repository = SVNRepositoryFactory.create(SVNURL
                .parseURIEncoded(url));

        ISVNAuthenticationManager authenticationManager = SVNWCUtil
                .createDefaultAuthenticationManager(username, password);
        repository.setAuthenticationManager(authenticationManager);

        return repository;
    }
}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 22, 2005

[Book] Robust Java

書籍情報


Robust Java

レビュー

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 20, 2005

[Derby] Derby メモ

Derby で調べた内容を少しだけメモ。 Derby 公式サイトにあるドキュメントを拾い集めただけ。

Derby environments

Derby には "embedded" モードと "server" モードで動作できる。 "embedded" モードはアプリケーション内部で起動されて、そのアプリケーション内でのみ使用可能なモード。"server" モードは単体でアプリケーションとして動作するモードで、複数のクライアントアプリケーションから使用可能。 コネクションの張り方やマルチスレッドなどで挙動が異なるらしい。

Environments in which Derby can run
http://db.apache.org/derby/docs/10.1/getstart/getstart-single.html#cgsquck70629
Connection Mode
http://db.apache.org/derby/docs/10.1/devguide/devguide-single.html#N16F6D

Derby Driver

Derby で使用できる JDBC ドライバは以下の 2 つ。

  • org.apache.derby.jdbc.EmbeddedDriver ・・・ "embedded" モード用ドライバ
  • org.apache.derby.jdbc.ClientDriver ・・・ "server" モード用ドライバ
Available drivers
http://db.apache.org/derby/docs/10.1/getstart/getstart-single.html#rgsquck35368

Database connection URL

URL の書式は以下の通り。

jdbc:derby://<server>[:<port>]/databaseName[;URLAttributes=<value> [;...]]
Database connection URL
http://db.apache.org/derby/docs/10.1/getstart/getstart-single.html#rgsquck30197

Derby プロパティ

Derby を実行する際に指定できるプロパティ一覧。

java -Dderby.system.home=c:\\derby ...
の様に JVM 起動時に指定するか、
Properties props = System.getProperties();
props.setProperty("derby.system.home", "c:\\derby");
の様にアプリケーション中から指定する。derby.properties という設定ファイルに記述することもできる。
Derby properties
http://db.apache.org/derby/docs/10.1/tuning/tuning-single#ctunproper22250

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

[Library] コンテンツ移動のお知らせ

http://www.in-vitro.jp/blog/index.cgi/Library/20050920_01.html はこちらに移動しました。
Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 19, 2005

[Library] コンテンツ移動のお知らせ

http://www.in-vitro.jp/blog/index.cgi/Library/20050919_01.html はこちらに移動しました。
Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

[Derby] Derby にチャレンジ

Derby とは

Derby は 元 CloudScape と呼ばれた RDBMS。 IBM が Apache に寄贈したもの。 Pure Java で DBMS 自体のサイズが 2M と小さいのがステキ。

Derby
http://db.apache.org/derby/

Derby の実行環境構築

  1. Derby(derby.jar) をクラスパスに追加

サンプルコード

package jp.in_vitro.codelets.derby;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class Codelet {

    private static final String DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";

    private static final String PROTOCOL = "jdbc:derby:";

    public Codelet() {
        super();
    }

    public static void main(final String[] args) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {

        Codelet me = new Codelet();
        me.execute();
    }

    protected void execute() throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {

        // Derby を embedded モードで起動する。
        this.initializeDBMS();
        try {
            try {
                // テーブルの生成。
                this.createTable();
            } catch (SQLException e) {
                // 既に Table が生成済みの可能性があるので・・・
            }
            // insert
            this.insertRecord();
            // update
            this.updateRecord();
            // select
            this.selectRecord();
            // delete
            this.deleteRecord();
            // テーブルの削除。
            this.dropTable();
        } finally {
            // Derby のシャットダウン
            this.destroyDBMS();
        }
    }

    protected void initializeDBMS() throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {
        Class.forName(DRIVER).newInstance();

        Connection connection = null;
        try {
            connection = DriverManager.getConnection(PROTOCOL
                    + "derbyDB;create=true");
            connection.commit();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void destroyDBMS() throws SQLException {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(PROTOCOL
                    + ";shutdown=true");
            connection.commit();

        } catch (SQLException e) {
            // Derby が正常終了すると SQLException が発行される。
            System.out.println("" + e.getLocalizedMessage() + " : "
                    + e.getErrorCode());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected Connection getConnection() throws SQLException {

        Connection connection = null;
        Properties props = new Properties();
        props.put("user", "me");
        props.put("password", "password");

        connection = DriverManager.getConnection(PROTOCOL + "derbyDB", props);
        connection.setAutoCommit(false);

        return connection;
    }

    protected void createTable() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement
                    .executeUpdate("CREATE TABLE sample(field01 INT, field02 VARCHAR(10))");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void insertRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("INSERT INTO sample VALUES (999,'dummy data')");
            statement.executeUpdate("INSERT INTO sample VALUES (888,'hogehoge')");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void updateRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement
                    .executeUpdate("UPDATE sample SET field01=100 WHERE field02='dummy data'");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void deleteRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("DELETE FROM sample");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void selectRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            ResultSet rs = statement
                    .executeQuery("SELECT * FROM sample ORDER BY field01");

            while (rs.next()) {
                System.out.println("field01=" + rs.getString(1) + ", field02="
                        + rs.getString(2));
            }

            rs.close();
            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void dropTable() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("DROP TABLE sample");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

}

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 17, 2005

[Library] Pure Java DBMS

Pure Java の RDBMS を探してみた。 探してみると結構な数がある。 hsqldb は以前試してみたことがあるが、イマイチ使い勝手が良くなかった。 というわけで、他の RDBMS を試してみよう。

hsqldb - Original License
http://hsqldb.org/
Derby - Apache License, Version 2.0
http://db.apache.org/derby/
Mckoi - GPL
http://mckoi.com/database/
QED - Original License
http://www.quadcap.com/home.html
tinySQL - LGPL
http://sourceforge.net/projects/tinysql/
One$DB - LGPL
http://daffodildb.com/one-dollar-db.html

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 15, 2005

[Library] Jsch にチャレンジ

JCIFS とは

SSH2 用の Java ライブラリ。 SFTP、SCPなどにも対応している優れもの。

Jsch
http://www.jcraft.com/jsch/index.html
Jsch のサンプルコード
http://www.jcraft.com/jsch/examples/

JCIFS の実行環境構築

  1. Jsch(jsch-0.1.23.jar) をクラスパスに追加。

サンプルコード

package jp.in_vitro.codelets.jsch;

import java.lang.reflect.Field;
import java.util.Vector;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.HostKey;
import com.jcraft.jsch.HostKeyRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class Codelet {

    public Codelet() {
        super();
    }

    public static void main(final String[] args) throws Exception {

        Codelet me = new Codelet();
        me.connectSsh("192.168.1.1", "myname", "mypassword");
    }

    public void connectSsh(final String hostname, final String username,
            final String password) throws SecurityException,
            NoSuchFieldException, IllegalArgumentException,
            IllegalAccessException, JSchException {

        JSch jsch = new JSch();

        Session session = null;
        while (true) {
            try {
                session = jsch.getSession(username, hostname, 22);
                session.setPassword(password);
                session.connect(3000);
                break;
            } catch (JSchException e) {
                if (e.getLocalizedMessage().indexOf("UnknownHostKey") >= 0) {
                    // 無理矢理 known_host に登録。ホントはマズい。
                    HostKey hostkey = session.getHostKey();
                    HostKeyRepository hostkeyRepo = jsch.getHostKeyRepository();
                    Field field = hostkeyRepo.getClass().getDeclaredField(
                            "pool");
                    field.setAccessible(true);
                    System.out.println("" + field.getType());
                    Vector hostkeyRepoPool = (Vector) field.get(hostkeyRepo);
                    hostkeyRepoPool.add(hostkey);
                    session.disconnect();
                    continue;
                }
                break;
            }
        }

        Channel channel = session.openChannel("shell");
        channel.setInputStream(System.in);
        channel.setOutputStream(System.out);
        channel.connect();
    }

}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 14, 2005

[Book] Programming Java Virtual Machine

書籍情報


Programming Java Virtual Machine

レビュー

Java の bytecode が何故動作するのか、という Java の世界における根本的な解説を提供してくれる一冊。 最近は Ease of Development(EoD) の旗印の下、コーディングを簡単に、簡単にという動きが強い。 ただ、現実には依然として bytecode レベルの知識がないと理解できないことも多い。 VM の知識というと毛嫌いする人も居るが、Java で真面目に生計を立てたいのなら是非一読を薦めたい。

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 10, 2005

[JSR] JSR 181 Web Services Metadata for the Java Platform ダイジェスト

Web Services Metadata for the Java Platform の仕様をざっと眺めたときのメモ。

JSR 181 Web Services Metadata for the Java Platform

オリジナルの入手はこちら → JSR 181

Concepts

Server Programming Model

Web Services Metadata

Annotation: javax.jws.WebService
Annotation: javax.jws.WebMethod
Annotation: javax.jws.Oneway
Annotation: javax.jws.WebParam
Annotation: javax.jws.WebResult
Annotation: javax.jws.HandlerChain
Annotation: javax.jws.soap.SOAPBinding
Annotation: javax.jws.soap.SOAPMessageHandlers

Java Mapping To XML/WSDL

SOAP Binding

Mapping JSR-181 to the J2EE 1.4 Runtime Environment

Using JSR-181 annotations to affect the shape of the WSDL

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 02, 2005

[Book] UML Distilled

書籍情報


UML Distilled

日本語翻訳版


UML モデリングのエッセンス

レビュー

UML の入門書としては非常に名の通った書籍なのでご存知の方も多いだろう。 この本の良いところは、UML の解説は入門に徹しつつもきちんと現実的な解説を織り込んでいるところ。 下手に何冊も UML の書籍を読み漁るよりも、この一冊を丁寧に読む方が良いと思う。

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 27, 2005

[Library] JCAPTCHA にチャレンジ

JCAPTCHA とは

CAPTCHA を Java で実現するためのライブラリ。 CAPTCHA というのは、completely automated public Turing test to tell computers and humans apart の略で通信相手が人間かコンピュータかを判断するための機構のこと。 Hotmail やら GMail やらを登録する際に表示されるクネクネした画像とかでお馴染みのアレ。 この辺りに解説がある。

Captcha - Wikipedia, the free encyclopediaの翻訳(2005年2月27日版)
http://www.memb.jp/~deq/voice/captcha/wikipedia-captcha.html
はてなダイアリー - CAPTCHA とは
http://d.hatena.ne.jp/keyword/CAPTCHA

JCAPTCHA は簡単に CAPTCHA を実現できるらしいのでチャレンジ。 内部で EHCACHE という別のライブラリに依存しているらしいので、それも必要。

JCAPTCHA
http://jcaptcha.sourceforge.net/
EHCACHE
http://ehcache.sourceforge.net/

JCAPTCHA の実行環境構築

  1. JCAPTCHA (jcaptcha-all-1.0-RC2.0.1.jar) をクラスパスに追加
  2. EHCACHE (ehcache-1.2beta2.jar) をクラスパスに追加
  3. その他必要なライブラリ (commons-collections-2.1.1.jar, commons-logging-1.0.4.jar) をクラスパスに追加

実行例

↓のサンプルコードを動かしてみたところ。 [↓のサンプルコードの実行例(1)] [↓のサンプルコードの実行例(2)]

サンプルコード

package jp.in_vitro.codelets.jcaptcha;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.Locale;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;

import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;

import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

public class Codelet {

    public Codelet() throws CacheException {
        super();
    }

    public static void main(final String[] args) throws Exception {
        CaptchaImageCreator creator = new CaptchaImageCreator("my id", Locale
                .getDefault());

        ImageViewer viewer = new ImageViewer(creator);
        viewer.setVisible(true);
    }

    public static class CaptchaImageCreator {
        private String captchaId;
        private Locale locale;

        public CaptchaImageCreator(final String captchaId, final Locale locale)
                throws CacheException {
            super();

            this.captchaId = captchaId;
            this.locale = locale;

            this.initializeEhcache();
        }

        protected void initializeEhcache() throws CacheException {
            // ehcache-1.2beta2.jar 内にある XML ファイルで EHCACHE を初期化する。
            InputStream is = this.getClass().getResourceAsStream(
                    "/ehcache-failsafe.xml");
            CacheManager.create(is);
        }

        public BufferedImage createImage() {
            // イメージを生成する。
            ImageCaptchaService service = new DefaultManageableImageCaptchaService();
            BufferedImage image = service.getImageChallengeForID(
                    this.captchaId, this.locale);
            return image;
        }
    }

    public static class ImageViewer extends JFrame {
        private BufferedImage image;
        private CaptchaImageCreator creator;
        private Canvas canvas;
        private JButton nextButton;

        public ImageViewer(final CaptchaImageCreator creator) {
            super();

            this.creator = creator;
            this.initComponents();
        }

        protected void initComponents() {
            // ウィンドウ終了方法の指定。
            super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            // 初回イメージの生成。
            this.image = creator.createImage();

            // ContentPane の設定。
            Container contentPane = super.getContentPane();
            contentPane.setLayout(new BorderLayout());

            // イメージ表示用キャンバスの準備。
            this.canvas = new Canvas() {
                @Override
                public void paint(Graphics g) {
                    g.drawImage(ImageViewer.this.image, 0, 0, this);
                }

                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(ImageViewer.this.image.getWidth(),
                            ImageViewer.this.image.getHeight());
                }
            };
            contentPane.add(this.canvas, BorderLayout.CENTER);

            // "次のイメージに進む"ボタンの準備。
            this.nextButton = new JButton(new AbstractAction("next image") {
                public void actionPerformed(final ActionEvent evt) {
                    ImageViewer.this.image = ImageViewer.this.creator
                            .createImage();
                    ImageViewer.this.canvas.repaint();
                }
            });
            contentPane.add(this.nextButton, BorderLayout.SOUTH);

            // ウィンドウサイズの自動調整。
            super.pack();
        }
    }
}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 25, 2005

[Book] Ship It!

書籍情報


Ship It!

レビュー

CMM だの RUP だのアジャイルだのといった書籍が持てはやされているが、「実はこれで十分なのでは??」と感じさせる一冊。 開発チームの体制から心構え、SCM や Build Process の必要性といった現場発の現実的な開発の在り方を紹介している。 どの内容も目新しさは感じないが、全体を通して読むと「なるほど」となる。 技術的な深さを抑えてある分読みやすい。 いわゆる開発プロセスなんていうものは、このレベルが当たり前になって「さて、次をどうするか」という状況で考えるものではないだろうか。 分厚い RUP の書籍を手に取る前にまずこちらを試してみて欲しい。

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 19, 2005

[DocBook] DocBook メモ

DocBook とは

ドキュメント記述用に規定された XML の標準フォーマット。 DocBook でドキュメントを記述しておくと、ツールを使用して HTML や PDF、RTF など様々なフォーマットに変換できるためにドキュメントのポータビリティが向上する。

既に現在のプロジェクトでは DocBook を導入済みで実績もあるのだが、より広範囲に使用したいので再調査。 出来れば DocBook → HTML、PDF、MS Word の変換を出来る環境を整えたい。 環境の構築(Word への変換は自作??)からメンバーの教育まで、難所が多そうだ。

DocBook 参考資料

Docbook 公式サイト
http://docbook.org/
Docbook Specifications ・・・ 様々なバージョンの仕様書
http://docbook.org/specs/index.html
DocBook 5.0: The Definitive Guide
http://docbook.org/tdg5/en/html/docbook.html
DocBook XSL Stylesheets
http://docbook.sourceforge.net/projects/xsl/
DocBook で文書を書こう!
http://members.at.infoseek.co.jp/zzyyb/docbook/

Posted in DocBook | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 18, 2005

[JSR] JSR 94 Java Rule Engine API ダイジェスト

Java Rule Engine API をざっと眺めたときのメモ。

JSR 94 Java Rule Engine API

オリジナルの入手はこちら → JSR 94

6. Definitions

Rule Engine
高機能な if/then statement インタプリタの様なもの。ビジネスロジックをシステムの外部に出すことで宣言的プログラミング(declarative programming)を促進する。
Rule
Rule は condition と action とから成る。この JSR では Rule の構造は規定されない。
Rule Execution Set
Rule の集合。この JSR では Rule Execution Set の構造は規定されない。
Rule Session
Rule Engine とクライアント間の実行時コネクション。Rule Session は単一の Rule Execution Set と関連付けられる。
Stateful Rule Session
Stateful な Rule Session。
Stateless Rule Session
Stateless な Rule Session。Stateful Rule Session よりシンプルでパフォーマンスが良い。

10. Architecture

  • javax.rules, javax.rules.admin とい 2 つのパッケージで構成される。
  • javax.rules は、Rule Engine のランタイムクライアントを表す。既に用意された Rule Execution Set 用の Rule Session の生成や Rule Session を用いた各種処理を提供する。
  • javax.rules.admin は、管理用 API を表す。外部リソース (URI, InputStream, XML, Binary tree, Reader) から Rule Execution Set を読み込む機能を提供する。

10.1. Runtime API

RuleServieProviderManager
RuleServiceProvider を提供する。ベンダー毎の RuleServiceProvider を返す。
RuleServiceProvider
RuleRuntime, RuleAdministrator を提供する。
RuleRuntime
RuleSession, 登録済みの RuleExecutionSet の URI リストを提供する。
RuleExecutionSetMetadata
RuleExecutionSet に関するメタデータを提供する。
RuleSession
StatefulRuleSession, StatelessRuleSession の共通インターフェース。
StatelessRuleSession
クライアントは StatelessRuleSession に Objet のリストを渡して RuleExecutionSet の実行を指示する。その後、処理の結果生成された Object を受け取ることができる。処理結果の Object は ObjectFilter を利用することで必要なもののみ受け取るようにフィルタリングすることができる。
StatefulRuleSession
RuleExecutionSet に渡される Object の受け渡しなどを行うインターフェース(addObject, getObject, removeObject, updateObject, containsObject)を提供する。
ObjectFilter Interface
RuleSession 実行結果 Object リストから必要なもの/不必要なものを選別するフィルタ。
Handle Interface
StatefulRuleSession 内で独自の方法で Object を識別する。異なる ClassLoader でロードされた Object 同士でも正確に一致/不一致を判断するために利用される。

10.2. Administrator API

RuleAdministrator
RuleExecutionSetProvider を提供する。
RuleExecutionSetProvider
RuleExecutionSet を生成する。
LocalRuleExecutionSetProvider
RuleExecutionSet を生成する。LocalRuleExecutionSetProvider はシリアライズされていないデータ (InputStream, Reader) から RuleExecutionSet を生成する。
Rule
Rule の名称や説明情報などを提供するインターフェースを持つ。
RuleExecutionSet
RuleExecutionSet の名称や説明情報などを提供するインターフェースを持つ。

クラス図

[JSR 94 クラス図]

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 16, 2005

[Library] PDFBox を試してみる

PDFBox とは

PDF の読み書きから暗号化、復号化までしてくれるスグレモノの Java 用ライブラリ。 基本機能で少し遊んでみた。

PDFBox
http://www.pdfbox.org/

PDFBox の実行環境構築

  1. PDFBox(pdfbox-0.7.2.jar) をクラスパスに追加。

サンプルコード

既存 PDF の読み込み
1 byte 文字のみで構成されている PDF を読み込んで JPEG に書き出してみた。 何とも簡単に出来た。
日本語 PDF の書き出し
1 byte 文字のみの PDF 書き出しはサンプルにあったので、2 byte 文字の書き出しにチャレンジ。 TTC 形式のフォント(TTF ファイルの集合) は読み込めないので、予め BREAKTTC というツールで TTF を作成しておいた。 結局、上手く行かないまま時間切れ。(↓のコードは文字化けした PDF を出力する)。
package jp.in_vitro.codelets.pdfbox;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import org.pdfbox.exceptions.COSVisitorException;
import org.pdfbox.pdmodel.PDDocument;
import org.pdfbox.pdmodel.PDPage;
import org.pdfbox.pdmodel.edit.PDPageContentStream;
import org.pdfbox.pdmodel.font.PDFont;
import org.pdfbox.pdmodel.font.PDTrueTypeFont;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class Codelet {

    public Codelet() {
        super();
    }

    public static void main(final String[] args) throws COSVisitorException,
            IOException {

        Codelet me = new Codelet();
        me.createJapanesePDF(new File("c:\\workspace\\japanese.pdf"), new File(
                "c:\\workspace\\MSGOTHIC_FONT00.ttf"));
        me.convertPDFtoJPEG(new File("c:\\workspace\\english.pdf"));
    }

    public void convertPDFtoJPEG(final File target) throws IOException {

        PDDocument document = null;
        try {
            document = PDDocument.load(target);
            List pages = document.getDocumentCatalog().getAllPages();

            int count = 0;
            for (PDPage page : pages) {
                BufferedImage image = page.convertToImage();
                FileOutputStream fos = new FileOutputStream(target
                        .getAbsolutePath()
                        + "." + count++ + ".jpg");
                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fos);
                encoder.encode(image);
                fos.close();
            }
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }

    public void createJapanesePDF(final File target, final File fontFile)
            throws IOException, COSVisitorException {

        String message = "日本語だよ。";

        PDDocument document = null;
        try {
            PDPage page = new PDPage();
            document = new PDDocument();
            document.addPage(page);

            PDFont font = PDTrueTypeFont.loadTTF(document, fontFile);

            PDPageContentStream contentStream = new PDPageContentStream(
                    document, page);
            contentStream.beginText();
            contentStream.setFont(font, 10);
            contentStream.moveTextPositionByAmount(50, 50);
            contentStream.drawString(message);
            contentStream.endText();
            contentStream.close();
            document.save(target.getAbsolutePath());

        } finally {
            if (document != null) {
                document.close();
            }
        }

    }
}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 15, 2005

Aug 14, 2005

[JSR] JSR 73 Data Mining API ダイジェスト

Data Mining API の仕様をざっと眺めたときのメモ。

JSR 73 Data Mining API

オリジナルの入手はこちら → JSR 73

1. Overview

  • JDM は Pure Java のデータマイニング用 API。 データマイニングツールベンダが提供する実装に対する共通の API を定義する。
  • 類似の JSR に JSR-69 JOLAP があるが、JSR-73 は JSR-69 と調整をしながら策定されている。
  • JDM は、API(application programming interface)、DME(data mining engine)、MOR(mining object repository) の 3 つのコンポーネントで構成される。

2. Use cases

3. Concepts

Data mining Functions
データマイニングの主だったサブドメイン。以下の 5 つから構成される。
  • Classification・・・予め決められた分類に従ってデータを分類する。ex) customer segmentation, business modeling, credit analysis
  • Regression・・・時間を考慮したClassification。ex) financial forecasting, biomedical and drug response modeling
  • Attribute Importance・・・モデルの構築の際にどの属性が最も重要であるかを決定する。
  • Clustering・・・データ内のクラスタを見つける。
  • Association・・・データ内に頻発する値の関連を見つける。ex) market basket analysis
Data mining Tasks
  • Building a model
  • Testing a model
  • Applying a model
  • Object import and export
  • Computing statistics on data
  • Verifying task correctness
Principal Objects
  • Connection
  • Task
  • Execution handle and status
  • Physical data set
  • Physical data record
  • Build settings
  • Algorithm
  • Algorithm settings
  • Model
  • Model signature
  • Model detail
  • Logical attribute
  • Logical data
  • Attribute statistics set
  • Apply settings
  • Confusion matrix
  • Lift
  • Cost matrix
  • Prior probabilities
  • Category sets
  • Taxonomy
  • Rules
  • Verification report
Physical data representations
  • Individual record
  • Single record case table
  • Multi-record case table
  • Data preparation
Attribute mapping
  • Direct mapping
  • Pivot mapping
Creating physical data objects
Persistence
Object references
Reflection/introspection

4. Packages

5. Code examples

6. Conformance statement

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 12, 2005

[Subversion] Subversion メモ

Subversion を導入して結構経つが、きちんとドキュメントを読んだことが無い。 一度読んでおかないと、ということでメモ。

Subversion 公式サイト
http://subversion.tigris.org/
Subversion によるバージョン管理
http://subversion.bluegate.org/doc/book.html
Subversionの基礎練習
http://www.hyuki.com/techinfo/svninit.html
TortoiseSVN
http://tortoisesvn.tigris.org/
Subclipse
http://subclipse.tigris.org/

Posted in Subversion | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 10, 2005

[Book] How Tomcat Works

書籍情報


How Tomcat Works

レビュー

まさにタイトルの通りの内容。 Tomcat はどのように動いているのかをコードレベルで解説している。 単純な Web Server の仕組みの解説から入り、Container、Connector、Lifecycle と言うように段々深化していく。 Tomcat は Java ServletJavaServer Pages の Reference Implementation だけあって、Code Reading の題材としては面白い。 ただ、そこそこ規模が大きいので取っ掛かりが大変。 この書籍は、その取っ掛かりとしてかなり重宝した。 コーディング技術の向上に壁を感じたら読んでみると良い一冊。

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 09, 2005

[Blosxom] Bloxsom Autoattach plugin

autoimg を参考に添付ファイル用の plugin を作成してみた。

ダウンロード

autoattach.zip

インストール方法

bloxsom の plugin ディレクトリ内に解凍

使用方法

entry 内に "[" + 添付ファイル名 + "]" を記述する。添付ファイルは zip, lzh, gz を指定可能。

添付ファイルは以下の通り設置する。

bloxsom_home
   └entries ・・・ bloxsom の entry 設置用ディレクトリ
     ├myentry.txt ・・・ ファイルを添付される entry
     └myentry ・・・ entry と同一の名前でディレクトリを作成
       └attach.zip ・・・ 添付ファイルはここに設置

Posted in Blosxom | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 07, 2005

[Misc] 開発作業を整理してみる

さて、先日は開発環境を整理してみたので、次は開発作業を整理してみたい。 ここでの開発作業とは、アプリケーションの実装に必要なあらゆる作業のこと。 コーディング、テスト、ディプロイなど定常的な作業もあるし、ステージング環境の構築のような作業も含める。 定義が結構曖昧だけれど、要は「モノを作る人たち」の責務となる実装に焦点を当てた作業。 その辺りの作業をどこまで自動化できるか、どこまで手順化できるか整理しておきたい。

[開発作業]

★Project Task
プロジェクトスコープのタスク。Shared Environment 構築、Workspace Environment 構築、など。ここは自動化というより手順化。自動化してもコストに見合わないため。
Shared Environment 構築
一番最初に行うべきタスク。手順化しておいて手順書通りの作業を行うようにしておくのがベストか。
アプリケーション雛形作成
ディレクトリ構成や自動化されたタスクのスクリプト、各種ツール類の標準設定などを含んだアプリケーションの雛形を作成するタスク。自動化する範囲にもよるが結構な量の設定が必要となるのでテンプレートもしくはウィザードが欲しい。
Workspace Environment 構築
最低でも手順化は必要だが、開発者の人数が多い場合は必要なソフトウェアを自動インストールしてくれると便利か。
★Phase Task
イテレーション単位のタスク。リリース、結合テスト、コードレビューなど。ここは可能な限り自動化したいが、人手に頼る部分も大きい。
リリース
実行可能なモジュールとドキュメント、ソースコードなど納品物一式を整える。ビルドマネジメントツールで自動化する。Maven は標準でサポートしているのでカスタマイズだけで済む。
結合テスト
コードレビュー
基本的には人手で行う必要があるが、ツールでかなり広範なサポートが可能。Jalopy、CheckStyle、FindBugs、JLint、JMetric などで単純作業を減らす。
★Build Task
実装作業レベルのタスク。コンパイル、単体テスト、パッケージング、ディプロイなど。ここが一番自動化しやすい。このタスクは基本的にビルドマネジメントツールで自動化しておく。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 04, 2005

[Misc] 開発用ツールの選択肢

開発環境を構築するのに利用できそうなツールを各項目毎にリストアップしてみた。 (他にもあると思うが)この中から良さそうな組み合わせを考えてみたい。 まずは一通り実際の使用感を確かめないと・・・。

Shared Environment

SCM(Source Code Management) CVS, Subversion, VSS, StarTeam
Executable Code Management
Build Management Maven2, Maven, Ant, Antmod, Invicta, LuntBuild
Source Health Management CI(Continuous Integration) CruiseControl, DamageControl, Continuum, Hudson
Integration Tester Selenium, e-Test
Information Sharing Issue Tracker Bugzilla影舞, Scrab, TrackIt, jTrac
Feature Tracker Scrab
Document Management System
BBS/Wiki 【Wiki】Hiki, PukiWiki, YukiWiki, 【BBS】ClipBoard, MegaBBS

Workspace Environment

IDE(Integrated Development Environment) Eclipse, NetBeans, JBuilder, JDeveloper, Sun Java Studio Creator

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Aug 02, 2005

[Misc] 開発環境を整理してみる

[開発環境]

開発環境は意外とプロジェクト毎にマチマチになってしまっている感じがするので、一度 TO-BE 像を整理をしてみた。 適当に整理しただけなので、造語が混ざっていたりするがご愛嬌ということで。 これを基に一度環境の見直しをして、その結果をフィードバックしていきたい。 大手だと標準化されているのだろうな。

★Shared Environment
プロジェクトで共有される環境。

☆SCM(Source Code Management)
ソースコード管理システム。 プロジェクト成果物のバージョン管理を行う。 CVS, Subversion, VSSなど。
☆Executable Code Management
実行可能コード管理システム。 開発対象システムが依存する外部ライブラリの管理を行う。 Maven のリモートリポジトリなど。
☆Build Management
ビルド管理ツール。 Maven2, Maven, Ant, make, shell scriptなど。
☆Source Health Management
定期的にプロジェクト成果物のヘルスチェックを行う。
CI(Continuous Integration)
継続的インテグレーションシステム。 定期的に開発対象システムのインテグレーションを実行する。 CruiseControl, DamageControl, Continuumなど。
Integration Tester
結合テストツール。 実行可能な状態にされた開発対象システムに対して自動的に結合テストを行う。 e-Testなど。
☆Information Sharing
プロジェクトメンバー同士の情報共有機能を提供する。
Issue Tracker
バグやその他重要な事項を管理する。 Bugzilla影舞など。
Feature Tracker
システム要件を管理する。
Document Management System
ドキュメント管理システム。 各種CMS、Wikiなど。
★Workspace Environment
開発者毎に用意される環境。

☆IDE(Integrated Development Environment)
統合開発環境。 Eclipse, NetBeans, JBuilder, JDeveloper など。
☆Build Management
ビルド管理ツール。 Maven2, Maven, Ant, make, shell scriptなど。
★Staging Environment
ステージング環境。

Posted in Misc | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Jan 01, 2005

[n/a] Blog 管理者プロフィール

プロフィール

都内で開発者をしています。
語るべきことは特にありません。
語りたいことは特にありません。

略歴

  • 20世紀 誕生。
  • 20世紀 小学校入学。
  • 20世紀 中学校入学。
  • 20世紀 高等学校入学。
  • 20世紀 大学入学。
  • 20世紀 就職。
  • 20世紀 (転職){0-9}。
  • 現在 サラリーマン継続中。

Posted in n/a | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |