goo blog サービス終了のお知らせ 

N2 ToolBox(跡地)

跡地です。引っ越しました。http://d.hatena.ne.jp/nosen

Almost Plain Text

2004-08-22 14:22:49 | オープンソース
Maven2のドキュメントのディレクトリにはaptという謎のフォーマットのドキュメントが置かれています。調べてみるとこれは文書をWikiに似たプレインテキストの形式であるらしい。
このフォーマットの文書をいろいろな形式に変換するaptconvertというツールがhttp://www.xmlmind.com/aptconvert.html
から入手できます。
サポートされている出力フォーマットは一応HTML, LaTeX, PostScript, PDF, RTF, DocBook SGML, DocBook XMLと多岐に渡っています。

確かにxdocよりはずっと楽にドキュメントが書けてよさそうですね。

この手のツールは国際化に関する考慮が不十分なことが多いのですが、aptconvertは出力フォーマットがHTML、DocBookであれば文字コードがSJISの入力を受け付けることができます。XML形式に出来てしまえばあとはどうにでもなる話ですから、実用上はこれで十分でしょう。
ドキュメントも充実していて、すぐに使えます。

Mojoって何?

2004-08-12 01:13:00 | オープンソース
Maven2のソースコードを読んでるとそこかしこに"Mojo"という単語を見かけます。これは一体何なのでしょうか。

maven-core/docs/apt/mojos.apt

の記述によると、MojoとはMaven java objectsのことなのだそうです。"Mojo"の最初の"o"はどっから湧いて出たんだ!と突っ込みたくなりますが、誤解を恐れずにものすごく平たく言うと、一つのゴールを実行する責務を負うJavaオブジェクトというくらいの位置付けの様です。(間違ってたらご指摘ください)
例えば、maven jar pluginは

AbstarctJarMojo.java
JarMojo.java
JarDeployMojo.java
JarInstallMojo.java

という4つのJavaファイルから構成されています。AbstractJarMojoは抽象クラスなので、実質3つのMojoですね。そして、JarMojoはjarというゴールを実行するという具合にMojoとゴールは1対1の関係にあります。ですから、Maven2のプラグインはMojoのかたまりといえると思います。

面白いのは、個々のMojoが自分担当するゴールに関するメタデータをXDoclet風のJavaDocタグの形で保持しているという事です。
例えば、JarMojoのクラスコメントは以下のようになっています。
/**
* @goal jar
*
* @description build a jar
*
* @prereq surefire:test
* @prereq resources:resources
*
* @parameter
* name="jarName"
* type="String"
* required="true"
* validator=""
* expression="#maven.final.name"
* description=""
* @parameter
* name="outputDirectory"
* type="String"
* required="true"
* validator=""
* expression="#project.build.directory"
* description=""
* @parameter
* name="basedir"
* type="String"
* required="true"
* validator=""
* expression="#project.build.output"
* description=""
*
* @author <a href="michal@codehaus">Michal Maczka</a>
* @version $Id: JarMojo.java,v 1.10 2004/07/07 07:18:10 evenisse Exp $
*/
public class JarMojo extends AbstractJarMojo

見れば一目瞭然、ゴールの名前、説明、パラメータの名前、型、説明、パラメータが必須かどうか等の情報が書かれています。
これらの情報はmaven plugin plugin を使ってプラグインをビルドする時に、プラグインのjarのMETA-INF/maven/plugin.xmlの中に書き込まれます(多分ここでQDoxを使っているのでしょう)。
そしてこの情報はorg.apache.maven.Mavenインターフェースを経由して取得できます。これはeclipseなどのIDEにMavenを組み込む時にとても便利そうです。

JavaDocタグとして記述される情報の中で注目したいのが、@parameterにくっついている"expression"です。
ここでプログラム中から参照されるパラメータ名と実際に使用されるオブジェクトを紐づけています。V1ではプラグインのパラメータはほとんど全てシステムプロパティに設定されていましたが、Maven2では"expression"に指定された評価式をベースにOGNLを使用して取得されます。
OgnlProjectValueExtractorというクラスがOGNLを使って値をとってくる役目を担っています。

Mojoに関してはmaven2のメインのCVSにあるものの他にCodehausの中でもいくつか開発が進められているものがあるようです。
(http://cvs.mojo.codehaus.org/からソースが見れます。まだ準備中みたいですが、http://mojo.codehaus.org/というのもあります)

Subversionの活用案

2004-08-05 01:02:45 | オープンソース
いま関わっている仕事のドキュメント管理にSubversionを使ってみようかと思って、マニュアルを眺めているうちに、これはいろいろと面白い使い方が出来そうだと感じました。CVSと比べて良いのは、svnlookを使ってリポジトリの状態(特にディレクトリツリー全体に関わるもの)を細かく調べられることと、バージョン管理下のファイルやディレクトリ、リビジョンに"属性"という名前つきの値を付与することができることです。

これらの機能を上手に使えば成果物管理につきもののめんどくさい作業をちょっと自動化して楽に出来そうな感じがします。と言うわけで以下にアイデアを書きます。

1.成果物一覧の自動生成
svnlook treeの出力を解析してExcelに張り付ければ簡単にできそうです。属性として各ファイルに短い説明を付けておけばそれも一緒に表の形で表示できて良いでしょう。

2.変更履歴の自動生成
コミット時に変更されたファイル、その変更内容、変更者の情報をその都度どこかにとっておいて、あとでマージすることで自動的に生成できそうです。もちろん全リビジョンの情報をあとでまとめて取得しても良いでしょう。最終更新者、最終更新日などの情報は成果物一覧にマージして表示してもよいかもしれません。

3.変更の影響範囲の追跡
各ファイルに属性として自身の変更によって影響を受ける可能性のあるファイルのリストを保持しておき、そのファイルが変更されたときに、「影響を受ける可能性があるファイルとの整合性をチェックしてねー」という旨を関係者に通知できたら面白そうです。

1, 2 は簡単そうですが、3は少しめんどくさそうですね。

解剖! Maven2

2004-08-03 01:23:50 | オープンソース
やっとMaven2のソースコードを入手できたので、時間を見付けてちょこちょこと読んでいます。まだまだ開発途上といった感じなのですが、大体何をやろうとしているのかは分かります。
Maven V1のソースコードは1行も残っていないのではと思います。

Maven2の一番の特徴はPlexusというDIコンテナを使ったコンポーネント指向のモデルを採用している点だと思います。
Plexusが他のDIコンテナと比べて特徴的な点はField InjectionというDependency Injectionの方式を推奨しているところです。
これは、プライベートフィールドに直接依存コンポーネントをInjectしてしまうというかなりきわどい方式です。おかげでMaven2のソースコード中にはどこで初期化されているのか分からないプライベートフィールドが多発しているため、直接Injectされていることを突き止めるまでは相当悩みました。
正直なところ、Field Injectionを前提としてクラスを設計してしまうと、もはやそのクラスは普通のJavaオブジェクトとしては使えなくなってしまうので、イマイチなんじゃないだろうか?と思っています。Plexus自体は一応Constructor Injection/Setter Injection共にサポートしているようです。

Plexusの設定はjarファイル中のMETA-INF/components.xmlに記述することになっている様です。添付の画像はmaven2のコア部分を構成する主要なコンポーネント間の依存関係を示したものです。
コンポーネントは互いのインターフェースにのみ依存しています。
Maven自体もコンポーネントになっているので、他のツールへの組み込みはV1の時より随分楽になっていると思います。

V1の位置付けは基本的に「Antスクリプト再利用フレームワーク」で、スタンドアロンの利用を前提としたものでした。
例えば、mavenをサーバ側において、サーブレットと同一VMで起動したい場合、普通にmavenの中でSystem.exitをやってくれているため、maven終了と同時にTomcat終了という事態が発生ていました。

maven2では少なくともそういう事はなさそうです。
プラグイン自体が、従来はプラグインリファレンスのWebサイトにのみ掲載されていたような、自分自身の使い方に関する情報を持てるので、IDEとの統合もずっと楽そうです。

maven2はAntスクリプト再利用という枠を越えてもっと汎用的な何かを目指そうとしていると思われます。

Maven2のビルド

2004-07-30 03:58:42 | オープンソース
---
昨日投稿した記事が中途半端な状態で表示されていました。
すいません。投稿しなおします
---

ようやくMaven2の実態が少しずつ見えて来ました。
まだまだ開発途上という雰囲気ですが、

http://cvs.apache.org/viewcvs.cgi/maven-components/

でソースコードが見れます。
現在ものすごい勢いで開発がすすんでいるようです。

ビルド方法はCVSから落として来たディレクトリから、

m2-bootstrap-all.bat

でビルドできます。
ただし、あらかじめホームディレクトリにmaven.propertiesというプロパティファイルを作成して、maven.homeとmaven.repo.localの二つのプロパティを設定する必要があります。
maven.homeはmaven2のインストールディレクトリ、
maven.repo.localはローカルリポジトリの位置を指定します。
mboot.jarというのはつい最近コミットされたPureJavaのmaven専用ビルドプログラムです。(その前はビルド用のプログラムはbashスクリプトでした)

使い方は現在調査中でまだ詳しいことは分かっていません。
ソースコードをざっと眺めた所、今までとは見違えるように美しいコンポーネント指向のモデルに生まれ変わっているようです。
それにしてもmaven2が依存しているライブラリは
plexusを始めとして、classworlds, xstream, qdoxなど、
CodeHaus産の物が多いですね。Jakarta産はCommons-Cliくらいなのではないでしょうか。これも時代のながれというものでしょうか。

RubyでServlet(続き)

2004-06-21 21:46:53 | オープンソース
WEBrickを使って動的なページを生成するには、AbstractServletや手続きオブジェクトをHTTPServerに登録する他に、erbを使う方法があります。erbというのはJavaでいうところのJSPの様なもので、テキスト文書の中に <%~%>で括ってRubyスクリプトを埋め込みます。JSPと同じように<%=~%>で括られた式が返す文字列は文書に埋め込まれます。HTTPServerはデフォルトで拡張子rhtmlのファイルをerbスクリプトとして扱うようになっています。

例えば、ドキュメントルートにhello.rhtmlという名前で以下の内容のファイルが置いてあるとします。
Hello, <%= query["name"] %> 
HTTPServerがポート2000で起動しているとき、ブラウザで
http://localhost:2000/hello.rhtml?name=Nose
を開くと、
パラメータの部分がテキストに埋め込まれて、
Hello, Nose
ときちんと表示されるはずです。他にもWEBrickから呼ばれるerbスクリプトの中では、servlet_request, servlet_responseという変数名でそれぞれHTTPRequest, HTTPResponseオブジェクトが使用できます。WEBrickのソースコードは短いので、APIの詳細を調べるにはソースを追ってしまった方が早いと思います。
機能的にはいたってシンプルで、JavaServletのようにリクエストのディスパッチや、セッションのような仕掛けはどうも見当たりませんでした。この辺をサポートするフレームワーク的なものがあるといいなぁと思っていたら、
DIVなどというものがあることが発覚。dRubyとerbを使ったちょっとしたWebアプリケーションフレームワークだということです。作者はerbを作った人らしいです。そういえばこのDIVというフレームワーク、昔なにかの雑誌の記事で見掛けたような気がする。。。

RubyでServlet

2004-06-20 02:45:57 | オープンソース
ずっとJavaの話ばかり書いてますが、僕は実はRubyも大好きです。
Windows上でシェルスクリプトがわりに良く使うのですが、
Rubyでプログラムを書くたびに、その出来の良さに感激しています。作者のまつもとさんは凄い人です。
他の言語のようなプログラミング特有の辛さがなく、自然な思考の流れを妨げられずに楽しくプログラミングができるのです。

いつも、Rubyをもっといろいろな分野で使えないかと思案していて、例えばRubyでServletみたいなことができたら、Webアプリケーションのプロトタイプ開発などに威力を発揮するのじゃないかと思っていました。

で、そんなライブラリを探してみたら、ruby1.8からWebrickというrubyでServletのようなことを実現できるライブラリが標準の添付ライブラリになっていることに気が付きました。Webサイトにのっていたサンプルを見る限りはでは、JavaServletに似たインターフェースで簡単に使えそうです。
Javaと違って、web.xmlのようなややこしい設定ファイルが無いのは手軽でいいと思います。あと、クロージャをServletのように使えるのは結構熱いですね。
eRubyとかと組み合わせるとJavaServlet+JSPのようなことも簡単にできそうです。
おもしろそうなので、これに関してはもう少し突っ込んで調べてみたいと思います。
なお、僕が普段家で使っているDebian sarge でaptを使ってRubyをインストールした場合、webrickはruby本体とは別のパッケージで配布されてるみたいなので、注意が必要です。

apt-get install libwebrick-ruby

でインストールできます。

BeanShell2.0の機能(続き)

2004-06-16 23:45:33 | オープンソース
BeanShell2.0では、スクリプト内でクラスが定義出来るようになったついでに、クラスパス上の.javaファイルを必要に応じて勝手に読み込んでクラスを生成するという荒技が可能になりました。
使いどころがいまいち思い付かないのですが、とにかく凄い。

こちらは、もっとすぐ使えて便利そうなのが、オブジェクトインスタンスのインポート機能。たとえば以下のようなコードが可能になります。
hello() {
    importObject(new HashMap());
    void sayHello() {
        print("hello, world ");
    }
    return this;
}
h = hello();
h.put("key", value");

importObjectの引数で渡されたオブジェクトのインスタンスメソッドは実行時のスコープにインポートされます。ここではHashMapのメソッドがhello()というScriptingObjectにMix-Inされているのが分かります。
これは素のJavaクラスとBeanShellスクリプトとの連携に新たな可能性を開く、非常に面白い機能だと思います。

あと、細かいですが、JDK1.5のstatic importが使えるようになりました。
static import java.lang.Math.*;
 sqrt(4.0);
このコードがJDK1.4でも1.3でも動く、というところがミソです。

BeanShell2.0の機能

2004-06-16 01:43:59 | オープンソース
最近、Groovyを試したりしてたのですが、いろいろあってまたすっかりBeanShell派に戻ってしまいました。機能の豊富さ、易しさ、柔軟性は他のJavaで実装されたスクリプト言語に比べても抜群にいいと思います。アイディア次第でいろいろな用途に使える、非常にパワフルなツールです。
今日は、そんなBeanShellの最新版、2.0b1の新機能について調べてみました。
目玉はスクリプトの中でクラスを定義できる様になったことです。
しかも、クラス定義には普通のJavaのコードだけでなくBeanShellのルーズな文法も使えます。さらに、クラスのメソッドの中で使用されるコマンドや変数は、実行時のコンテキストで評価されます。
例えば、以下のようなスクリプトが可能です。

class HelloWorld {
    void sayHello() {
        print("hello " + name);
    }

    void doCommand() {
        sampleCommand();
    }
}

sayHelloメソッドの中の変数nameや、doCommandメソッドの中のコマンドsampleCommandがクラス定義の中に含まれていないことに注意してください。このスクリプトを"classTest.bsh"という名前で保存したとして、bshプロンプト上から以下のようなコマンドを実行することができます。
bsh % source("classTest.bsh");
bsh % hw = new HelloWorld();
bsh % hw.sayHello();
hello void
bsh % name = "nose";
bsh % hw.sayHello();
hello nose
変数nameを後付けできていますね。
同様に、つづけて以下のコードも可能です。
bsh % sampleCommand(){print("execute!");}
bsh % hw.doCommand();
execute!

普通のBeanShellスクリプトは構文木をあらわすJavaオブジェクトとして表現されているのですが、この場合だけは動的にクラスを生成しているようです。バイトコードの生成にはASMが使われていたりします。普通のJavaクラスなので、同じ名前のクラスを2回定義しようとすると怒られます。そういうことがやりたい時はおとなしくScriptingObjectを使え、ということなのでしょう。
いろいろきわどいことも試してみたのですが、GroovyのようにImcompatibleClassChangeErrorとかは発生しませんでした。
大体のコードは想定通り動きそうです。
良く考えてみると、クラス以外のBeanShellスクリプトはJavaオブジェクトの世界で表現されているので、普通のやり方ではバイトコードの世界にはたどり着けそうにないから、当然と言えば当然です。

多分Groovyの気難しさは全てのスクリプトを一旦バイトコードに変換しているところから来ているような気がしてるんですね。バイトコードはどうしても動的な性質が制限されますから。
Rubyのような動的な言語を期待していた僕としては、その辺がいまいちしっくり来なかったというのも、BeanShell派にもどった理由の一つですね。まぁ、Groovyに関しては今後の発展に期待というところでしょうか。

GroovyとBeanShellの比較

2004-06-06 22:48:16 | オープンソース
BeanShellもGroovyと同様にJavaで実装されたスクリプト言語です。Javaに似た文法を使えるという点で、両者は似通っていますが、もちろんいくつかの点で違いがあります。

Groovyが「Javaに似た文法+Rubyのような文法」を目指している
のに対して、
BeanShellはJavaと完全に同じ文法のスクリプト言語を目指しています。ですから、Groovyの様にクロージャは使えないですし、セミコロン、かっこの省略もできません。ですが、BeanShellはBeanShellでJavaの文法+簡略化された文法を許しています。たとえば以下のようなものです。
・型のない変数
・プリミティブ型のAutoBoxing/Unboxing(JDK1.5と同等)
・forループの拡張(JDK1.5と同等)
・JavaBeansプロパティやMapへの簡略化されたアクセス

また、Groovyのクロージャと同等の機能として、ScriptedMethodというのがあります。以下のGroovyとBeanShellのコードは同等です。
(Groovy)
hello = {println("hello, world")}
hello()

(BeanShell)
void hello() {
  print("hello, world");
}
hello()


また、スクリプトの内部表現もかなり異なっています。
BeanShellがスクリプトを構文木として表現し、Javaオブジェクトへのアクセスにリフレクションを使用するのに対し、Groovyではスクリプトを一旦Javaのクラスに変換します。このため、Groovyスクリプトにはバイトコードにコンパイルすることが出来たり、パフォーマンスの向上などのメリットがありますが、その一方で。BeanShellよりJavaVMの制限を直接受けやすくなっており、ちょっと変なことをやるとすぐIncompatibleClassChangeErrorとかが発生してしまいます。

個人的にはBeanShellの方が機能も豊富だし、スクリプト言語らしい動的なプログラミングもやりやすいので好みです。動的にクラスパスを変更したり、クラスパス上においてある.javaファイルを読み込んだりといった機能は強力ですし、APIもGroovyよりわかりやすいと思います。ただ、Groovyの文法はやっぱり魅力で、手続き的な処理はBeanShell、宣言的なものはGroovyというように、当面は目的に応じて使い分けて行くことになりそうです。