Apache だけじゃない...
2007.09.28
ヘヴィなネタが続きましたから、今回は軽いネタで。
Apache 製の(言い方変ですが)各種ツールに日々お世話になっているのは言うまでもないことですが、それでも「オープンソース≒Apache」と言ったらかなり言いすぎというものでしょう。Apache にもいろいろとライバルがいます。
JBoss だって、独立したオープンソースソフトウェア・コミュニティだと言えます。傘下に Hibernate が居ますものね。あと、ここには Java バイトコードを編集して AOP ができちゃうライブラリである javassist が Incubator に居たりします。これ東工大の千葉滋という先生がリーダーをしていたりして、親近感がありますね...
とはいえ、最大のライバル...となると、Codehaus でしょうか。ここのフラグシップは Apache が Apache と Tomcat であるように、Jetty になるのかなぁ....で、Apache のスポンサーが IBM...というのは有名ですが、Codehaus は Weblogic で有名な BEA が大きなスポンサーにいたりします(他にもいろいろ...)。ここの傘下のプロジェクトというと、
- JVMの上で動くスクリプト言語である Groovy
- ミニJavaコンパイラであり、断片コードをJavaバイトコードにしてくれる Janino
- 一時注目されたことのある DBとXMLを無差別にオブジェクト・バインディングしてくれちゃう Castor
- バイトコード織り込み型AOPフレームワークの AspectWerkz
- Apache James が使ってた「簡単に任意のサーバを作るフレームワーク」だった、Avalon-Phoenix の後身である Loom
- XPathエンジンとして有力視されている Jaxen
- コメント内に書かれた Doclet 風の MetaData をランタイムから参照して何かをさせるフレームワークの MetaClass
- MetaClassを使って DI コンテナの機能を指定する DIコンテナの DNA
などなど、結構面白めなプロジェクトが目白押しです。
そういえば、Apache 傘下の ActiveMQ が Codehaus 出身だったり、Apacheの次期フラグシップ?な Geronimo の内部で Codehaus の XMLパーサである Woodstox が使われていたり...とか、意外にハタから見るほど、「強烈なライバル意識」みたいなものはないのかもしれませんね。
まあ、たまにはこういう記事もいいかも。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.28 14:01
RSS, 401 Authorization Required!!!!
2007.09.27
RSSを使ってクライアントプルで○○を配信する、というウマミを憶えてしまったからには、RSSでパスワード保護された情報を配信したい...となるのはこれ当然の流れなのですが、まだこの問題については決定的な解決、というものはないようです。
実際、メジャーなブラウザでも、IE7, FireFox 2 は、認証付きRSSのサポートは未だ...という状態で、Opera のみ Basic 認証付きRSS が読める現状です。まあ、勿論スタンドアロンな RSSリーダーで、認証付きRSSが読める...というのはありますから、「使えるものを使え」というのが一番正しい姿勢なのかもしれません。
と思っていたら、こんな回避策がありました。
feedproxyとは、HTTP Basic認証がかかっているRSS/Atomフィードを、HTTP Basic認証未対応のreaderでも読めるようにするサービスです。
これ要するに、認証対応の HTTP プロキシです。ですから、このプロキシに対して、取得先のURLと、認証アカウント、認証パスワードを登録しますが、悪用を防ぐために、認証アカウントはプロキシサーバに保存せず、パスワードをアカウントで暗号化して、URLとペアでDB保存するもののようです。
ですから、アカウント名と、作成後に渡されるアクセスキーとをURLに含んだ、この feedproxy のURLにアクセスすると、オリジナルのパスワードが正しく復号されて、アクセスキーで検索されたURLに Basic 認証付きでアクセスして、その結果を呼び元に流す、という仕組みです。
一応安全性とか考慮はされてますが、これも要するに、内部で持つべきパスワードを外部に(そこそこ安全なかたちですが)置いて、Basic認証を代行させる、というやり方のわけです....やりにくいところを外部に投げたようなかたちですね。ですから、自分がアクセスする feedproxy の URL が流出したら、他人でも簡単にヒミツのRSSが見えてしまうことになるので、パスワード並みの管理が必要になることは、言うまでもないです....結論しちゃうと、一時しのぎの便法、という感想を持つのではないでしょうか。
あるいは、こんなのどうでしょう? ちょっと OpenID のやり方にヒントを受けたのですが、RSS配信の Servlet(とか動的機構)が、RSSリーダに対して、認証をさせるためのサーバにリダイレクトする....とはいえ、RSSリーダはかなり機能が制限されているようで、リダイレクト対応がされていない....これいいアイデアとも思いますけどねぇ、ブラウザの現行対応が追いついてないです。
まあ、やろうと思えば、クッキー認証という手がありますが、スタンドアロンのRSSリーダも IEコンポーネントを使っている....から、クッキーを引き継いで使えるか、というとそうでもないものが多いようです。要するに、一番単純なかたちでしか、スタンドアロン RSSリーダは HTTPをハンドリングできない模様です。まあ、クッキー認証だったら、ブラウザ内蔵の RSSリーダは問題なく使えるようです。
こんな風に、「RSSと認証」というのは未だに結論が出てない....という雰囲気です。さっさとメジャーブラウザのRSSリーダが、Basic認証対応しちゃえばいいんですけどね。
Bloglines流の
http://username:password@example.com/path/to/feed
というURLで認証する、っていうのは下の下です。もちろん、お分かりですね!
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.27 11:58
final のススメ
2007.09.26
パズルです。ありがちなことですが、Java プログラムで修正が発生しました。その内容は、
古いインターフェイスを廃止したので、新しいインターフェイスに派生クラスを書き換えるべし
というものです。が
- 1. 派生クラスの数が半端じゃないです。
- 2. この派生クラスの全部に修正対象メソッドがあるわけではなく、それは確認しなきゃならない...
- 3. その派生クラスがアプリ全体に散らばっていて、一覧するのも厄介だ....
というケースで、一番簡単な対象クラスのチェックはどうすればいいでしょう?
(今風に回答がすぐに見えないように改行入れます)
それはですね、
廃止対象メソッドを、final 宣言してコンパイルする
というやり方です(苦笑)。final 宣言されたメソッドは、「上書き禁止」ですから、廃止メソッドを含んだクラスはすべてコンパイルエラーになります。ですから、それをツブしていけばいいわけで、修正後さらにコンパイルすれば、修正落ちがないことも確認できるわけです。
この使いかたはちょい邪道ですが、final 宣言自体は結構使いでのある Java 言語仕様だってご存知でした? この使い方は、後々同じ継承クラスを使う人に、「このメソッドは上書きすべきでない」ことを、伝えるというのが本来の意味ですが、それを作業上先取りすれば、こういうことも出来ちゃうわけです。まあ、それだけではなくて、final 宣言は、
- 1. いわゆる Immutable なデータオブジェクトの作成のときに使う。これメチャ重要なテクニックですから、憶えるといいですよ。
- 2. ユーティリティクラスなどを final class として宣言する
- 3. 上書きしたらそのクラスの意義を失うようなメソッドであることを、特に使う人に伝えたい
というような「基底クラスを作ったプログラマの意図」を、継承クラスの作成者に伝える、というあたりでの重要な機能を持っているわけです。final 宣言の一番よく使われるケースは言うまでもなく、
ある変数を定数扱いにしたい
というものですが、それの陰に隠れるはもったいない機能がいろいろとある...というのを使って実感してみましょう!
とはいえ、変数引数の final 宣言については、私の立場は「付けない方がいい」です.....だってあれ、昔ながらの「C言語で const 修飾は付けるべきか?」問題と同じで、付けてもインスタンスへの直接の代入を検出するだけで、本来「こうだったらいい」仕様の「インスタンスの中身の全般的な変更不可」は全然実現できないわけです。だったら final 引数宣言は(内部無名クラスに渡す引数の制限で使うケースは別として)無意味であり、誤解の元のように思います...
どっちか言えば、「この引数はこのメソッドで積極的に変更される」というのを明示するような、そういう修飾がある方のが有益のような気がします....(あ、そういうアノテーション作るって意味ありますね)。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.26 17:35
バグの正体は...
2007.09.25
今の仕事が、リリース直前状態になったために、プログラマとしての仕事は開店休業中です。もしバグが見つかれば冷や汗で緊急対応ですが、でなけりゃ暇....という一面うらやましいような状態なんですね(苦笑)。
で、その前にやってたプロジェクトのバグハンターを依頼されました。症状はなかなか過激なものです(詳細は秘密)。一見、Tomcat のセッション管理が狂ってる...ような見かけのもので、他のアクセス者の情報が見えてしまうものでした。
それを追っていると....要するに、struts のカスタムタグの落とし穴でした。
カスタムタグはロジックをコンパクトにまとめて再利用する非常に強力な武器です。しかし、そのライフサイクルがちょっと謎なんですね。何となく、カスタムタグを呼んだときに、クリアな状態で初期化されているように思いがちなのですが、実はカスタムタグはプールして使われます。言い換えると、Aさんがアクセスしたのと同じページに、別なBさんがアクセスすると、プールされた同じインスタンスが使われてしまいます。
Aさんがあるカスタムタグを使った後で、セットしたメンバ変数(たとえばカスタムタグ属性はメンバ変数にセットされます)は、実はそのままBさんのカスタムタグにそのままあります。しかし、タグ属性に定義されたメンバ変数の場合、必ずそのメンバ変数はBさん側の JSP 記述にしたがって、Bさん向けのデータで上書きされてから、doStartTag() なり doEndTag() が呼ばれるわけです。ですから、セットされるメンバ変数が その JSP の中で同じものである限り、特に他人のデータが残っている、という現象は起きないわけです(これがフツーの状態です)。
しかし、カスタムタグ属性以外にメンバ変数があって、タグ属性の値によってそのメンバ変数の値が初期化されたりされなかったりするケースでは、セットしたつもりのない値が参照されてしまう...ということもありうるわけです。
フレームワークを使う場合の、暗黙の心得として、
どうしても必要な場合以外には、メンバ変数を作るな!
というものがあります。このケースは余計なメンバ変数を定義していて、勿論それは本質的にローカル変数に書きなおせるものなのですが、その初期化条件がすべてを網羅していないために、他人の情報が残ってしまった...というわけなのですね。
ふう、症状は派手でしたが、とんだ地味な理由でした。勿論余計なメンバ変数をローカル変数に直したら、症状は解消!でした。
カスタムタグはプールされて使われる上に、release() はコンテナの都合で呼ばれたり呼ばれなかったりする....というわけなので、若干偏執的と言われても、TryCatchFinally を implements して、doFinally() で確実にすべてのメンバ変数を初期化するように書くのが防御的プログラミングというものでしょう。
ほんとはここらへん判りづらいし、アドオン的な interface にしかないdoFinally() に事後的初期化をさせる...というのはややカスタムタグの仕様ミスのような気がしないでもないですね.....
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.25 21:12
オレオレは詐欺?
2007.09.21
以前も少しだけ紹介しましたが、前から OpenID って気になっていたんですね...でちょっとマジメに調べだしたんです。
で....ちょっと気になるのは、
もし、すべての問い合わせに「認証する!」と答えちゃう OpenId 認証サーバがあり、その認証サーバを使う End User、たとえば http://happy.hacker.com がいるとしたら、その OpenID、 http://happy.hacker.com は誰でも使えてしまい、誰ででも「私が http://happy.hacker.com です」とサービスをだますことができてしまう....ということになるようです。まあ、勿論、http://happy.hacker.com はそういうリスクを犯して、「勝手に他人が自分の名前を名乗ってイイよ!」と言っているわけですねぇ。
で、そういう問題を扱ってるページがないか?と思って調べたのですが、ちょっと面白いものがありました。→どんぞこ日誌
ここでは、
それから重要なのが、現状のOpenIDは認証として完結しないということ。OpenIDは「今日コメントしたボブと名乗る人物は、昨日コメントしたボブと同じURLを管理下におく誰かです」ということしかわからないわけです。このボブと名乗る人物がbob@example.comを所有しているかどうかはわからない。
と衝いてます。で、
それから、個々人が設置するOpenIDの認証サーバは原則として全て「オレオレ」なので、OpenID(あるいはそれに類する認証方法)を使う場合に、どの程度の信頼性をFOAF認証に期待するのかを考えないといけないですよね。
となるわけですが、ここで出た「オレオレ」という表現がウケているみたいです。この記事を受けて、
あと、オレオレ問題なんですけど、オレオレOpenIDサーバをテストするというのはどうでしょうか。
全ての認証結果に1を返すSpamオレオレサーバは、どんなURLに対する認証が来ても1を返すと思うので、ありえないURLを与えて認証するかどうかを自動で監査してやるというのは。
もちろん、認証要求がきたその時に監査して、というのは手順に時間もかかりますし、簡単に対処できてしまうのでアレですが、
Blacklist的なものを作る際に、単に被害報告を待つのではなく、積極的に監査する手段があればいいかなと。
なんてコメントもついてます。確かに、OpenID の認証というのは、「オレオレ」な認証で、それを信用するかどうか、はかなりリスキーな雰囲気ではあるわけです。
けど、「オレオレ・サーバ」って何か表現としてイイでしょ(苦笑)。萌えてます。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.21 18:09
おせっかいの罪(FireFox2編)
2007.09.20
今の仕事はリリースが近づいていて、最終チェックに余念のない状態なのですが....
こういうときに出るものですね、クリティカルなバグ。
出てきたのはちょっと厄介な問題です。それは、FireFox 限定の問題で、
パスワードマネージャが、意図しない password フィールドを勝手に置換し、変更したつもりがないのに、パスワードが変えられる
というものです。FireFox 2 のパスワードマネージャが、見えないところで勝手に password フィールドにパスワードを補ってしまい、それがパスワードを盗むのに使われてしまう....というセキュリティ問題は、かなり大きく取り上げられていて、
セキュリティを気にするなら、パスワード自動補完は使うな!
という記事が、ネットの上で良く見られます。これと同じ原因で、
パスワード認証して入る Web アプリで、自分がマスター管理者として、サブ管理者をいろいろ作って、サブ管理者のパスワードを作成する
というコンテキストだと、Web アプリの中に、自分のものではないパスワード入力フィールドがあることになります。このとき、入り口のパスワード認証で、パスワード自動補完がなされていると、FireFox は、
パスワード自動補完を求められるホストでは、とにかく <input type="password" ..../> を見つけたら、勝手に登録されたパスワードを補ってイイのだ!
と考えて、ログインするのに使ったパスワードを自動的に入れてしまいます。ですから、他のフィールドを変更して保存したりすると、変えるつもりもないサブ管理者のパスワードを、入り口のパスワード認証で使ったパスワードに勝手に差し替えてしまいます....
これ、困ります。要するに、補完パスワードの管理単位が、「同一ホスト、同一パスワード」というかなり広い単位でしか管理されていない....というのが、間違いの根源です。しかもこれが、デフォルト動作だったりするわけです。勿論パスワードフィールドは、例によって「*****」で隠されてますから、勝手に変えたことにさえ、操作者が気が付かないこともあります。
回避策は一応、
<form action="...." autocompete="off" >
というように、もともとIE独自の属性である autocomplete を form や input タグに与えれば、イケるのですが、その場合でさえ、すでに入り口で補完パスワードを設定してしまっていると、これも効かずに勝手に補います。ですから、
あるホスト(Webアプリ)全体で、パスワード補完しないようにする
しか手がありません。まあ、struts とか使っていると、struts の <html:form> にはこういう autocomplete なんていう規格外の属性はありませんから、カスタムタグで対応するしかないわけです....おせっかいは、とんだ迷惑ですね。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.20 21:14
RSS形式でログ配信
2007.09.19
さて、以前少し予告したことがありますが、Log4j での RSSAppender を書いてみました。これの説明は「Lo4J徹底解説 -- RSSを出力せよ」をごらんになるといいでしょう。
で、今回のネタは、RSS でログ配信をするとき....の問題です。
要するに、ログが大量に出てしまって、RSS リーダーが出力に埋もれてしまうよな状況が現れる可能性があるわけですね。たとえば「Webアプリが例外を投げたケースはすべてログ」をする場合、人気の Web アプリだったら、
同じ箇所で例外を投げた報告のRSSが大量に発生する!
という嫌らしいことになります。勿論、そういうログをメールで送るなんてことをしてたら、MUA を起動したくもなくなる....(そういうわけには行きませんが)なんてことになりますよね。
これ以外にうまい解決があるように思います。それは、RSS(Atom含む)のエントリが、何で区別されるか....ということと関連します。
要するに、あるエントリが、他のエントリの更新ではなくて、新しいエントリである、というのを識別するのは、いわゆる guid(globally unique identifier) です。RSS諸形式に明示的に guid エレメントがない場合は、link エレメントのURL が guid として扱われるわけですよね。ですから、これを悪用(苦笑)しましょう。
たとえば、ログ本文に当たる内容を、MD5のようなハッシュ関数で処理して、決まった長さのフィンガープリントを作り、それを適当な URL の フラグメントとして guid を作る...というのはどうでしょうか。そうすればハッシュ関数の特性である
入力が同じならば、絶対に出力が同じだけど、入力が少しでも違えば、出力が大きく違う
性質から、「ちょっと長すぎるよね」で多少短縮してもおおむね大丈夫でしょう。
そうすれば、
違った位置から投げられた例外報告のみ、エントリとして RSS リーダから見える
というトリックを仕掛けることができるかも....
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.19 15:08
Janino はいかが?
2007.09.18
さて、連休で時間もあったことで、少し懸案のホームページの更新をしてましたが、その中で以前少し紹介した Logbackのフィーチャーをいろいろ見ていたところで、面白い機能がありました。それは、ログイベントに対するフィルターが、設定ファイルにこんな風に書けちゃうのです(ま、変わった log4j.xml だと思って読んでください....)。
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator name="myEval">
<expression>
message.contains("billing")
</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
%-4relative [%thread] %-5level %logger - %msg%n
</pattern>
</layout>
</appender>
....これほんと、Javaコードの断片のわけですね。Javaコード断片をXMLの中に書くことで、ログメッセージの中に「billing」という文字列を含むかどうか、というフィルターを作っちゃっているわけです。このように、Javaコード断片を自前で処理して、設定ファイルをよりユーザフレンドリ(というか、プログラマ・フレンドリですね)にしているわけです。この部分、 Janino というミニJavaコンパイラで <expression> の中身をコンパイルして、直接実行してフィルターの評価としています。
(ミニ)Javaコンパイラ、というとどれほど凄いライブラリか...と思うと、実際にライブラリサイズは 500M弱ですから、最近定番の Hibernate や Spring の巨大さと比べたらカワイイものです。これは使い方次第で流行るかも....という予感があります。
まあ、Java 6 で JavaScript を評価する Rhino が統合されたことを考えると、設定ファイルにこういうかたちでコード断片を埋め込んで何かさせる、という開発手法を今後は「設計の選択肢」として考慮に入れていくべきかもしれませんね。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.18 21:17
シリアライゼーション・Memo
2007.09.14
オブジェクト・シリアライゼーションといいますと、Java で生成したインスタンスをファイルにそのまま保存したりとか、ネット越しに転送したりとか、結構いろいろと使われている技術だ、ということは皆さんもご承知のことでしょう。たとえば EJB だと、シリアライゼーションされたオブジェクトを RMI を通じて送る、ということが技術的な根幹になっているわけですね。
ネット越しにオブジェクトを配信できる...ということは、逆に言えば、バイナリデータを保存できるDBでしたら、オブジェクトをそのまま保存する、なんてこともできるわけです。勿論、シリアライズされたオブジェクトはクラス情報とかいろいろ余計なものが入ってますから、単にDBに保存するにはあまり効率がいいやり方ではありません。各フィールドごとにバラして、テーブルの対応フィールドに保存した方がいいので、あまりDBに保存するためのオブジェクトとしては使われないのですが、やろうと思えばできるわけです。
とはいえ、「オブジェクトをネット越しに検索可能なかたちで配信する」という別な視点では、別な使い道がでてくるのでは?という視点はどうでしょうか。こう考えるのも、少し私が Apache DS(Directory Server →少し古いですが解説) について、情報を集めている...という事情があるのですね。この Apache DS は、Apache 版の LDAP サーバですが、LDAP プロトコルに縛られない汎用的な「ディレクトリ・サーバ」として開発されているものです。で、この Apache DS のウリの一つが「Java オブジェクトをそのまま配信できる」ということなのです。勿論、LDAP の強力な(けどややこしい....)検索文法などもフル装備で、階層的に整理されたかたちで管理できるのは言うまでもありません。
まあ、オブジェクト・シリアライゼーションという技術自体、今では PHP や Python のようなスクリプト言語だって装備しているような一般的な技術だったりするわけです。連休にでもちょっと試してみようかな。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.14 17:05
James君は開発の友
2007.09.13
Webアプリの必須項目として、
何か起きたらメールを送る
があります。ですから、開発中にいちいち職場の正規のメールサーバに問い合わせて..とやってると、本来の仕事メールが「開発用メールの海」におぼれてしまう...とか、ありますから、ローカルでメールサーバを立てる、ということもよくあります。
この時のオススメはですね、私は手前味噌ですが、James なんです。James は Apache で開発されている、Pure Java のメールサーバですから、「ローカル配信」という概念がまったくなくて、すべて仮想ドメイン・仮想アカウントで運用します。まあ、ローカル配信ではどうしてもシステムコールのお世話にならざるを得ないですから、そうなるのは当たり前なのですが、
作業用にテキトーなドメイン、テキトーなメールアカウントを作りたい
というニーズにハマるわけです。デフォルトが「仮想ドメイン」の方ですから、ローカル配信ベースで作られている一般メールサーバよりも、仮想ドメインにする設定がわかりやすい、というのもメリットですね。
しかも、これ、
一種のパイプラインによって、メールを好きなように処理し、好きなように加工できる
という強烈な機能を持ってます。とってもじゃないですが、Sieve なんてメじゃないです。この機能を Mailet と言いまして、私は自分で書いた InfoMailet というものをパイプラインに入れてますから、
メールが届いた時点で、James を起動したDOS窓に、Sender, Recipient, Subject が表示される。
という風にしています。ですから、メールを出した後に、わざわざMUAを起動して、メールを確認しなくても、MTA のレベルでウォッチできるようにしているわけです。勿論、他のメールサーバでもログを監視すればこれできるのですが、InfoMailet だと好きなように出力内容を選択できる、というのも大きなメリットです。
また、外部アドレスに向けて送信する...というのを作業上避けたい場合でも、少し設定をいじれば、それこそ外部アドレス向けメールをピンポイントで握りつぶす(なり自分宛に書き直しちゃったりする)なんて芸当も簡単です。
どうです、James を使ってみませんか?
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.13 09:30
恥ずかしながらドジりました....
2007.09.12
このタイトル懐かしいです。昔のCマガの人気連載でしたね。
で、昨日の「ドジ」の内容は、
エラーしたはずなのに、例外が補足されていない。
というものでした。システムのスタンドアロンで動作するサブプログラムでしたから、勿論ロギング対象として、
try {
.......いろいろ処理
log.info( "success" );
} catch( Exception e ) {
log.error( "ERROR!!", e );
}
としたわけですが、まったく結果ログが出ないのです(処理もされません).....意外な落とし穴でした。
実はこの中でやっている処理で、設定を読み込むスタティックなクラスがありました。このクラスでは一切インスタンスを作らないので、処理はこんな感じです。
public static List someList = initSomeList();
private static List initSomeList() {
...... 構築処理
}
で、この構築処理の中で呼んでいる別なスタティッククラスの中で、NullPointerException が起きてました。そうすると、catch 節で受け取る例外は、NullPointerException ではなくて、NoClassDefFoundError になってしまったのです! Error であって、例外ではないので、catch 節で捕捉されずに、そのまま死んでました(正確にはスレッドが死んでただけなので更に謎でした...)。
ふう、偏執的と言われようとも、こういうケースでは
} catch( Throwable e ) {
でないとダメなんですね....要するにクラス初期化の時点で失敗していたので、クラスが生成されずに例外ではなくて LinkageError になっちゃった、ということのようです。
恨み言を言えば、
こういう時、もっと判りやすいエラー(できれば例外)を投げてよ....たとえば java.lang.ExceptionInInitializerError あたり、願わくばClassInitializeException(こんなのない....)ならよかったのにね!
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.12 06:38
そのメールアドレスって実在するの?
2007.09.11
今回は特にスパム対策にも少し関連する話です。
メールアドレスについて、以前「形式的チェックはしようがない...」という話をしましたが、今回は形式的ではなくて実質的なアドレスチェックの話です。まあ、いわゆるスパムフィルターとも少し関連があるわけですけども、ここで扱うのはどっちか言えば Webアプリの入力フィールドで、入力される「メールアドレス」の正当性チェックの話題です。
普通 Web アプリを書いていると、単純に入力されたメールアドレスを RFC822 あたりでチェックして、(古いタイプの)形式的違反によってハネる、くらいの validation をかける、というケースもありますが、これは現状では「擬陽性」判定でユーザの意図に反してハネてしまう可能性がないわけではない、という結論でした。だったら、これは逆に、うまく Ajax でも使って、「実質判定」をした方がいいのでは?とも思えます。
ごく単純に「入力されたメールアドレスが正当かどうか」を判定する手段としては、
1. ドメイン名が正当かどうか。これはドメイン名から MX レコードを引いて、引ければOK。まあ、これに引っかかる入力は、入力ミスの可能性が高いでしょう。
2. MXレコードから引かれたそのドメインに対して、SMTP を発行して RCPT TO: が500番台のエラー(特に550 mailbox unavailable)を返さない。SMTP サーバによっては、存在しないアカウントについても受理することはありますが、送信可能なアドレスについてエラーを返すことは本質的にはない(スパム対策でややこしいことをしている場合は別ですが...たとえばグレーリスト処理とかSMTP遅延処理とか)ので、擬陽性判定は一般に大丈夫でしょう。念のためにトライする時の HELO するホスト名とか MAIL FROM: とかは、送信ドメインに関するチェックでハネられないように、ダミーではなくてなるべく「正当な」ものを使うべきでしょうね。
このくらいの処理ならば、そう処理も重くもならないので Ajax による回答待ちをして(まあ Action のServlet で正当性をチェックしてもいいけども)、正当性をチェックしても良いようにも思います。
Ajax でやった方がユニットとしての保守性・再利用性もありますから、そっちの方がいいのかな、という気もします。また、特に携帯アドレスで受信ドメインにまだ入っていないアドレスが入力されたときに、事前に「まだ受信が許可されてませんよ」とお知らせできる、というメリットもあるように思います。
ちょっとしたアイデアに過ぎませんが...意外にメリットが多くていいかも。
とはいえ、あまり一般的とは言えないSMTP遅延処理をしているケースは、このチェックが無意味に遅くなるので、困るのですけどね....
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.11 13:51
「非同期」という恩恵
2007.09.10
今回は少しこのところの概論みたいな内容です。
「Webアプリ」という分野が長らく仕事の大きなカテゴリになってきたわけですが、このところ少しニュアンスが変わってきた....ような気がしているのです。
特に Java での開発の場合「Webアプリ=Tomcat(ようなアプリケーション・コンテナ)」という感覚で、ずっと続いてきたのは言うまでもないことです。しかも、Tomcat の上に Struts のような「擬似シングルトン・コンテナ」を載せて使うわけですから、本質的にマルチタスクな HTTP サービスを、「あたかもシングルスレッドであるかのように」開発できる、という巨大なメリットがあって、Java のWebアプリが普及してきたわけです。勿論 Tomcat の功績は偉大です。
しかし、現在の開発トレンドをやや斜めから見たときには、「....必ずしも同期的なサービス・コンテナである Tomcat に束縛される必要はないのでは?」という疑問みたいなものが、このところ生じてきているようにも思います。まあ、そのきっかけになったのは、(ややコンテキストから離れるかもしれませんが)Ajax の普及でしょう。
実際、Ajax というのは「同期的なプロトコルである HTTP を、見かけ上非同期に扱う(Asynchoronous JavaScript + XML)」 のわけです。HTTPのリクエスト→レスポンスの完結を待って、結果処理をする、という流れではなくて、登録されたハンドラが「非同期に」処理完了のタイミングで呼び出されて処理をする、というやり方に「慣れて」きたことで、Webアプリケーション自体のニュアンスに少し変化が出てきたような気がするのですね。
ですから、同期的な Tomcat による Servlet 処理ですべてをやろう、とするのではなくて、「非同期なサービスも」いろいろと組み合わせて全体的に Web アプリを構築する、という方向が少し見えてきたような気がするのです。
この状況自体は、やはり全体的な技術的成熟でもあるわけでしょう。たとえば、Active MQ のようなスタンドアロンの JMS サーバを使ってみる...という(何でもしようとする JBoss ではなくて)のも選択肢に入る、という状況が、「(メール以外の)非同期サービス」というもの自体の復権(実は昔からあるわけで...)ともつながるのかもしれません。ですから、非同期処理に大きな位置づけのあるWebアプリ、というものも、可能性がかなり出てきた...ような気がしないでもありません。
非同期処理自体は、実際にはスケーラビリティの非常にいい、分散サービス向きの方法論です。ですから、今後負荷の大きなサービスに当たり前のように非同期で処理する...という風になっていくのかもしれません。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.10 15:16
諸行無常....(RSS4j)
2007.09.07
一時 RSS のハンドリングに、 Java ライブラリだと定番だったのが RSS4j でしたが、これ最近配布元の www.churchillobjects.com 自体が消滅しているようですね。まあ、RSS4j は Atom 非対応でしたし、RSS 2.0 も対応していない...というものでしたから、困る、といえば困るライブラリでしたが、何と言ってもネット上の情報がすごく多い(草分け効果ですね)ので、トッツキがいいライブラリだったのでしょうけど....
RSS4j に替わる Java ライブラリというと、こんなものがありますね。
| ライブラリ名 | 対応形式 | ライセンス | 備考 |
| Informa 0.7.0 |
RSS 0.9x,1.0,2.0 Atom 0.3 1.0 |
LGPL | 位置づけはベータ |
| ROME 0.9 | RSS0.90,0.91Netscape, RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, and Atom 1.0. | Apache | Sunの社員が中心のオープンソースプロジェクト。Sun が後援している。 |
| FeedParser | RSS 1.0 RSS 0.9 RSS 0.91 RSS 0.92 RSS 2.0 Atom 0.3 (deprecated) Atom 0.4 (deprecated) Atom 0.5 以降 OPML FOAF Changes.xml XFN |
Apache | Jakarta Commons の Sandbox にいるプロジェクト。かなり重装備。現状ではディストリビューションの配布はなくて、SVNリポジトリから取得するだけ。 |
| RSSLibJ 1.0 | RSS0.92のみ? | Apache | かなり怪しげ... |
穏当なところで ROME でやってみました。フツーにRSS,ATOMのエレメントをオブジェクトにしている、というノリのライブラリです。が、これ com.sun.syndication.feed.synd というパッケージがありまして、このパッケージを使うと、RSS と ATOM の区別がなくなって扱える...という面白いものです。
Jakarta の FeedParser は手を広げすぎの印象もありますし、Infoma と ROME の2強状態が続くのかなぁ....(Apache 系オープンソースプロジェクトでは、ROME採用の傾向が強いような印象だけど)
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.07 14:01
RSSAppender というアイデア
2007.09.06
ちょっと今仕事で使っている Bugzilla のようなバグトレースシステムで、「自分の担当のバグが登録されたら、それが判るように、RSS で配信したら...」というネタができました。まあ、イマドキのやり方ではありますね。そういう使い方というのは、
メールで知らせてくれるほど緊急ではないにせよ、定期的に忘れずにチェックできるといいね!
というくらいの緊急度の問題なのですね。プライオリティは高めでも、トップレベル、と呼ぶには少し及ばない....という出来事を通知する手段として、実はRSSというのはかなり便利なものだ、ということのわけです。
これは逆に考えると、例えば log4j のようなログツールの中で、こういう「RSSAppender」みたいな使い方が出来たら便利かな?ということでもあるわけです。実際、log4j の正規のディストリビューションにはまだ入っていないものですが、log4j の sandbox にある contribution に、Lara D'Abreo作の「RSSAppender」があります。また、Log4rss という log4j のRSSAppender としても使えるものを作っているという記事が見つかりましたが、このプロジェクトは今検索してみても見つからないです...
しかし、これらの実装は「RSSファイルに出力する」というやり方です。頻繁に更新されるかもしれない RSS ファイル(巨大なものになるかもしれませんね!)を、ログするたびに作り直すのは、かなり効率が悪いのでは....というのが心配です。ファイルに吐き出す RSS というアイデアは、私は少し疑問なんですね。
少し考えてみると、たとえば、一種のメモリAppender みたいな格好で、循環バッファで最大数を決めて運用し、外部インターフェイスで RSS 出力を得ることができるAppender だったら、これを Tomcat の servlet にしてリクエストに応じてRSSとして返してやる..という実装ができるのでは?とも思います。
勿論 Tomcat が落ちたら内容はクリアされますが、それはそれでもいいのかも。Servlet連用型、という感覚で、古いものは消えてもいいけど、新しいイベントは手軽にさっと一覧したい、というならば、意外に重宝な Servlet 外部監視ツールになるのかもしれません。何が俄然ヤル気になってきましたねぇ。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.06 21:44
ワタシはダレ?
2007.09.05
今回はかなり微妙な話です。
「あなたのお名前は?」と聞かれれば、記憶喪失でもない限り、自分の名前を答えられるのが、当たり前の人間です。が...「コンピュータの名前」となると、かなり微妙な問題がいろいろある、というのに突き当たってしまいました。
UNIX 系ならば、「マシン名」は /etc/hostname に書かれているのがこれだ、と言えますし、Windows ならばレジストリに書いてあるはずです。ここで Java のような「プラットフォーム独立」を謳う処理系での問題を考えると、OS互換性の問題がありますから、何か「うまくラップしたかたちで、マシン名を拾えるようにする」というのが、方法論になります。
で、Java の場合、java.net.InetAddress#getLocalHost()が、起動マシンのマシン名を取得する手段になります。このメソッドは native メソッドなので実装詳細はよく分からないのですが、挙動から推測するに Linux の場合、gethostname(2)を呼び出す仕様になっているようです。gethostname(2)は実質的に /proc/sys/kernel/hostnameを読んでいるようです。ここらへん、強引に/proc/sys/kernel/hostnameを書き換えると、/bin/hostnameの出力とInetAddress#getLocalHost()の戻り値に影響が及びますから、そういう感じの実装でしょう。
/etc/hostsを書き換えるなど、いろいろ実験してみましたが、getLocalHost()の挙動はこんな感じで実装されているようです。
- 1.gethostname(2)を呼んでホスト名を取得する。
- 2.そのホスト名で、ネームサービスを呼んで、IPアドレスに解決する。この時ネームサービスの呼び出しがセキュリティ的に出来なければ、localhost を返す。
- 3.解決されたIPアドレスから、もう一度ホスト名(ドメイン付きかも)に解決し、その最初のものを返す。
ですから、この戻り値はOSのホスト名解決のやり方にかなり依存します。LANをプライベートアドレスで運用している場合では、LAN内部でIPアドレスからホスト名に解決する時に、FQDN で解決することはフツーありませんから、プライベートアドレスで運用している時に、これが返すのは一般にドメイン付きではないでしょう。
JDKの古いバージョンですと、結構よくgetLocalHost()が「ループバックアドレスを返して困る...」という話があったようですが、今ではほとんどそういうことはないようです。勿論今でも、(非署名)Applet などでセキュリティ制限がかかるケースでは セキュリティ例外のハンドラの中でわざと localhost を返します。そういうことなので、まあ、一応OKなのかな?という気がしないでもないですが....
面白いことに、java.net.InetAddressには、getCanonicalHostName()というインスタンス・メソッドがあります。ここで、getLocalHost()で取得した「ローカルホストを表すInetAddress」を引数に渡して、このメソッドを呼ぶと、意外なことにこれが必ずしもgetLocalHost()のホスト名と一致するわけでもないのです。
ホントは、インターネットは「マシンの名前」なぞどうでもいい世界なのです。ですから、1つのIPアドレスに対して、複数の名前がエリアスで付く、というのは当たり前ですし、ですから、DNSの上での「C(ANONICAL)NAME」という概念があって、これがホストの「本名」に相当します。一見 Java の getCanonicalName()はこれを返すように見えて、実は全然そういうものではなかったりする...というのは、名前が悪いですね(実際には先ほどのgetLocalHost()みたいな流れで処理してます)。
しかも、「DNSの上のホスト名≠マシン名」という問題もあります。一台のマシンに、複数のネットワークカードを刺して運用する、というのは別に珍しいことでもありません。そうすると、DNSのホスト名はマシンなく、ネットワークカードのIPアドレス(これがカードのハードワイアドな識別子MACアドレスとLAN内部で結びつく)と対応しているわけです。「DNSのホスト名」はインターフェイスを識別するためのものであって、マシンを識別するためのものではない、ということなのですね。
これって、比喩的に言えば、「玄関から出て行った時にはAという名前で、勝手口から出て行ったときにはBという名前を名乗る人」みたいな状態のわけです(苦笑)。しかも、マシンの上から見たときには、「一度出て行って他人に聞かなければ、自分の名前が判らない!」ということにもなります...ここらへんが、かなりややこしいやり方でgetLocalHost()が自分の名前を解決しているベースのようですね。
あなたのお名前は何ですか?
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.05 12:14
Log4j vs Logback?
2007.09.04
オープンソース界って少し目を離していると、「激動」って感じで動いていることがありますね....
Apache だって、知らない間にかなり直下プロジェクトが増えてます。この間まで Incubator にいたよね..と思ってたプロジェクトが、正規プロジェクトに昇格したりとか(個人的には Roller の動向が気になる)、あるいは逆にプロジェクト廃止(Avalon廃止はもう結構前ですが...)だって、ないわけではないです(個人的には ApacheDS 動かしてみたいな)。
大定番の Log4j ですが、これも結構「危機?」というような状態が続いていたことは知る人ぞ知る...というものでした。ChangeLog を見てみると、一目瞭然です。
| 日付 | レビジョン | 概要 |
|---|---|---|
| 2007-08-24 | 1.2.15 | 修正約50件 |
| 2006-09-18 | 1.2.14 | 修正約30件 |
| 2005-12-04 | 1.2.13 | 修正2件 |
| 2005-08-29 | 1.2.12 | 修正約20件(traceレベル追加) |
| 2005-06-18 | 1.2.11 | 修正1件(build.xmlのバグ) |
| 2005-04-28 | 1.2.10 | (リリースされず) |
| 2004-11-01 | 1.2.9 | (1.2.8 と変わらない...) |
| 2003-02-19 | 1.2.8 | Log4j 普及のきっかけとなった定番バージョン |
実質的に、作業が 1.2.8 から 1.2.14 までの約3年半止まっていたような感じなのです。 ....これは要するに、1.2.8 までメイン開発者として、Log4j を「作って」きた、Ceki Gülcü が、「次期 1.3 に向けて....」で作ったα版で採用されたいろいろな新機能が、1.2 との互換性について他の開発者からの待ったがかかったために、Gülcü がヤル気をなくして、自身で別プロジェクト Logback を立ち上げた....というような事情があります。まあ、Gülcü 自身、log4j に対する愛憎みたいなものは、Wiki や Gülcü のメールに窺われます。
私は結構 1.3 で採用された JoranConfigurator って気に入っていたのですが、これも「あまりにハッキー」な先進機能過ぎた...というのが、1.2 開発継続のポイントだったようにも思います。XML 設定ファイルの構造を、newRule タグに追加タグの処理を行うハンドラを指定することで、変えれてしまう...というのも、ハッキーなフィーチャーすぎますよね。
そういう意味で、オープンソースプロジェクトでも、いろいろ(内部的に)難しいことが技術面以外である...というのを目の当たりにしたような印象です。ともあれ、新しい 1.2.14 以降のフィーチャーを理解して私のページに反映させなくちゃ。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.04 09:30
コントロールブレーク on OOP
2007.09.03
以前のエントリでも書いたネタですが、「コントロールブレーク on OOP」の汎用的なライブラリを書いてみました。コントロールブレークというと、懐かしの COBOL で「必須アルゴリズム教養」だったものですが、これを、
レベルごとの集計処理 → 非階層データの階層化
と捉えなおしてみると、意外に「イマのプログラミング」で使える道具になる感じがあります。というのも、これが、
DBという非オブジェクト指向非階層インターフェイス
と、
オブジェクト指向言語による階層的データ
との間のインピーダンス・ミスマッチをうまく解決するアルゴリズムになるのでは...というところですね。
| レベル1 | レベル2 | レベル3 | 値 |
| 関東 | 東京 | シナガワ | 11000 |
| 関東 | 東京 | シブヤ | 43000 |
| 関東 | 東京 | シンジュク | 21400 |
| 関東 | 横浜 | ツルミ | 9400 |
のような階層データがDBにあったとして、これを1回のスキャンで階層データを構築し、同時に各レベルごとの合計&総計を、階層データに付け加える...というのを、汎用的なライブラリで出来たら楽だよね~というのが、モチベーションだったわけです。
実際、このライブラリだと、指定の interface を implements したデータの List を引数に与えて呼び出せば、適切なフック(というかコールバック・ハンドラの方が判りやすい?)が
- 1. レベルENTER
- 2. 各行データの追加
- 3. レベルRETURN
で呼びされ、これらのフックが介入ポイントになって、独自の操作がいくらでもできるようになっている...という感じのライブラリです。
結構自分で書いて気に入っているものなので、ぜひぜひお使いくださいませ。
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.09.03 09:35





