Java で MD5

java.security.MessageDigest を使うと簡単。

MessageDigest md;
try {
    md = MessageDigest.getInstance(“MD5”);
} catch(NoSuchAlgorithmException e) {
    e.printStackTrace();
    return;
}
// digest を求めるバイト列設定
// update(“Hello, world!”.getBytes()) と同じ。
md.update(“Hello, “.getBytes());
md.update(“world!”.getBytes());
// 計算して求めるがそのままだとバイト列なので文字列化.
final byte[] digest = md.digest();
final String sHexDigest; {
final StringBuffer buf = new StringBuffer(“”);
    for(int i=0; i < digest.length; i++){
        final int n = digest[i] & 0xFF;
        if(n < 16) buf.append("0");
        buf.append(Integer.toString(n, 16));
    }
    sHexDigest = buf.toString();
}
 
System.out.println(sHexDigest);

JDB を使う

– 昨日の一件のおかげで初めて Java のデバッガを使うことに。
– デバッグ対象の JVM のオプションに

-Xdebug -Xrunjdwp:transport=dt_socket,address=50000,server=y,suspend=n

を追加して実行(Resin の場合は httpd.sh の args=”…” を -J-Xdebug -J-Xrunjdwp:…のように -J を付与)しておけば次のようなデバッグができる。

$ jdb -attach 50000

threads

グループ tcp-server:
  (java.lang.Thread)0x3b0 tcp-accept-8080 実行中
  (java.lang.Thread)0x3b1 tcp-accept-8080 状況待機中
  (java.lang.Thread)0x3b2 tcpConnection-8080-0 状況待機中

thread 0x3b2

tcpConnection-8080-0[1] suspend
すべてのスレッドが中断されました。
tcpConnection-8080-0[1] where
  [1] java.lang.Object.wait (ネイティブ メソッド)
  [2] com.caucho.server.TcpServer.accept (TcpServer.java:648)
  [3] com.caucho.server.TcpConnection.accept (TcpConnection.java:211)
  [4] com.caucho.server.TcpConnection.run (TcpConnection.java:132)
  [5] java.lang.Thread.run (Thread.java:534)
tcpConnection-8080-0[1] resume
すべてのスレッドが再開されました。

quit

という感じでかなり便利。
http://java.sun.com/j2se/1.4/ja/docs/ja/tooldocs/win32/jdb.html#description
– Sun JDK ドキュメント: jdb – Java デバッガ

JDBC のログとりメモ

– close() するのは PreparedStatement#close() でなく ResultSet#close() でもなく、絶対に Connection でなければならない。
– ログ情報には PreparedStatement#toString() がよさげ(少なくとも com.mysql.jdbc では)。
理由は、ログのための利便性から。SQLException がどのクエリでエラーになったかを残してくれないので、 PreparedStatement インスタンスがクエリ周りの情報をきっちり保持してくれていれば、toString() でログにどのクエリ文を実行したかが残せる。しかし、PreparedStatement#close() は DB 接続を閉じる仕様とは限らないため、Connection#close() を呼ぶ必要がある。PreparedStatement#close() だけにしたらプールがあふれ、思わぬ場所で DB 接続が開くのをずっと待ち続けることになってしまった。
– 例:

boolean isExist(int id){
    PreparedStatement ps = null;
    try{
        final Connection con = getConnection();
        try{
            ps = con.prepareStatement(“SELECT id FROM list WHERE id = ? LIMIT 1”);
            ps.setInt(1, id);
            return ps.executeQuery().next();
        }finally{
            con.close();
        }
    }catch(SQLException e){
        log(“Query error [“+ps+”]”, e); // void log(String, Throwable); とする
        return false;
    }
}

委譲とコンポジション(Effective Java の間違い)

Effective Java には、自身を参照にして渡さないと委譲とは呼べない、とあるが、これは間違い。Effective Java にも挙げられている [GoF P32] には次のようにある。

委譲では、1 つの要求を 2 つのオブジェクトが扱う。要求を受け取ったオブジェクトは委譲者へオペレーションを委譲する。これは、サブクラスが親クラスに要求を渡すことと同様である。

Effective Java にある自身の参照渡しはどこからでてきたのかというと、多分次の文の誤解から。

しかし継承の場合は、継承されたオペレーションは、C++ ならば this メンバ関数、Smalltalk ならば self を用いて、要求を受け取ったオブジェクトを参照できる。委譲でこれと同じ効果を実現するには、要求を受け取ったオブジェクトが自身を委譲者に渡す。そうすれば、委譲したオペレーションが受け手のオブジェクトを参照できるようになる。

その他参考:
<http://www.ogis-ri.co.jp/otc/otc2/oosquare-ml/Archive/200005.month/767.html>
– オージス総研 ML

Servlet の基本

– 基本は通常のクラスと同じだが、条件として javax.servlet.http.HttpServletを親クラスとする必要がある。
– protected void do*(HttpServletRequest, HttpServletResponse)
doGet, doPost, doDelete, doHead, doOptions, doPut, doTrace があり、それぞれ対応するリクエストのときに呼び出される。
– protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException
別のオーバーロードされた service メソッドから処理を受け、配分するのが役目なので protected。
parent.service(req,res) を呼び出した時点で do*(req,res) の処理が行われるので、その前後の共通動作を定義するのに便利。
– 日本語(マルチバイト文字)を引数にとる
— getParametervalues,getParameterを使い、化けた状態の文字を取得したあと

new String(string.getBytes(“ISO_8859_1”), “Shift_JIS”);

のようにする。(HTTPプロトコルの文字コードが ISO-8859-1 のため)
— HttpServletRequestクラスのsetCharacterEncodingで、パラメータを取得する前にエンコードを指定しておく。
— HttpServletRequest#setCharacterEncoding(String enc) の挙動の違いの問題に注意!
Tomcat 4.1.29 以降の 4.1.*/5.0.16以降の 5.0.*、では、Getメソッドではエンコードされなくなった。GETの引数はURIに含まれるので、URIはエンコードされるべきではないという見解による仕様変更とのこと。
– スレッドセーフということ。
サーバサイドでは1つのインスタンスを使いまわしてマルチスレッドで動作するので、スレッド同士の不要な干渉をなくさなければならない。
“staticではない”フィールド(インスタンス変数)もスレッド間では共有されている事に注意!
–> ページ閲覧者固有の変数を持ちたい場合、メソッド内で定義した変数を使わなければならない。
データアクセスなど同期を取らないといけない場合は、(デッドロックにくれぐれも注意しつつ)適宜 synchronized にする。

Java Applet で JavaScript コードを実行する

import java.applet.Applet;
import netscape.javascript.JSObject;
 
public class jstest extends Applet{
public void start(){
JSObject js = JSObject.getWindow(this);
js.eval(“alert(‘Hello, world!!’)”);
}
}

JavaScript を Java Applet にしてサイズ圧縮をうたい文句にしているソフトより。これなら JavaScript 上で Zip 圧縮/解凍して eval したほうがいい(jar って zip だし、肝心の JavaScript は Java コードのリテラルなので *.class に生で書かれているし)。

static ファクトリメソッドの落とし穴

Effective Java より、static ファクトリメソッドで Foo.getInstance() みたくするのがいい、とあったが、何も考えずやってると継承周りで混乱を招く。

class Parent {
public static Parent getInstance(){ return new Parent(); }
}
class Child extends Parent {}

このとき、Child.getInstance(); は Child インスタンスではなく(スーパークラスで定義されている getInstance() を使うため) Parent インスタンスを生成してしまう。
 
Effective Java の例にきっちり書かれているとおり、

class Parent {
private Parent(){ }
public static Parent getInstance(){ return new Parent(); }
}

とか class final Parent とかして継承を禁止するのが妥当な解決方法(拡張にはコンポジションを使う)。
それが嫌なら static ファクトリメソッドの公開をやめて普通にコンストラクタを公開する。
 
あるいは、継承を行うクライアントが、確実に public static Child getInstance() を定義してくれることを信じるか。

JDK1.5 の javadoc で package.html を指定すると複数のパッケージコメントのソースと言われて警告になる

– 正しく出力されるので害はないものの、毎回警告がでていたので調べてみた。警告内容は次の通り。

javadoc: 警告 – パッケージ “x.y.z” に複数のパッケージコメントのソースが検出されました。

英語だと以下。

Multiple sources of package comments found for package “x.y.z”

Java Forums <http://forum.java.sun.com/thread.jspa?threadID=599721&tstart=0> にずばり回答が。

Yep. The Doclet interface of the Doclet API specifies a method
 
void setRawCommentText(String text)
 
prior to 1.5 this method did exactly what its name implies. With 1.5 the implementation was changed to generate a warning and do nothing if it was attempted to set the comment text multiple times.
What happens is this:
Javadoc sees the package.html files in the sources, creates an appropriate Doc (PackageDoc) instance and sets the comment text. Then for some reason Javadoc encounters package.html files for already existing Doc instances and tries to set the comment text a second (third, fourth, …) time.
So, all you need to do is to ensure that Javadoc parses the package.html file for a given package only once, i.e. ensure that only sourcepath points to the package.html files but not classpath.

1.5 から package.html が複数見付かった時に上書きしつつ、警告を出すようになったとのこと。
ここで例にあるとおり、 javadoc のオプションで、 sourcepath でパッケージのある場所を示しつつ、なおかつ classpath でも示していたのが原因だった。Eclipse ではリリースディレクトリにも package.html をコピーしてくれていて、結局それが source のものと重複してしまった。
 
そもそも不要な、classpath からリリースディレクトリ(bin)の指定を外して解決。

javadoc でパッケージの説明をつける

– package.html というファイルを、指定したいパッケージのソースディレクトリに入れれば自動で読みとってくれる。<body> ~ </body> の最初の文を、概要のほうのパッケージの一行説明に使い、それ以外はパッケージの説明ページに使われる。
<http://java.sun.com/j2se/1.5.0/ja/docs/ja/tooldocs/windows/javadoc.html#packagecomment>
– javadoc – Java AAPI ドキュメントジェネレータ: パッケージコメントファイル
JDK1.2 から利用可能。

FreeBSD で java/linux-sun-jdk14 を使っていると "Can’t detect initial thread stack location" が出る原因

– make で表示されるインフォメーション通りにやっていないと jar で出たりする。

FreeBSD JDK, in ports/java/jdk14.
 
This Java VM will attempt to obtain some system information by
accessing files in linux’s procfs. You must install the Linux
emulation procfs filesystem for this to work correctly. The JVM
will exhibit various problems otherwise. This can be accomplished
by adding the following line to your /etc/fstab file:
 
linprocfs /compat/linux/proc linprocfs rw 0 0
 
and then, as root, executing the commands:
 
kldload linprocfs
mount /compat/linux/proc

説明通り、 /etc/fstab に

linprocfs /compat/linux/proc linprocfs rw 0 0

を追加して
$ mount /compat/linux/proc
を実行すればよい。