2008年7月3日木曜日

jar ファイルの場所を見つける方法

自作の jar ファイルに含まれたクラスを使うとき、その jar のパスやディレクトリを知りたいと思ったことありませんか?

かなり昔に作った自作ライブラリの一部ですが、最近、思い出したように使ってみて便利だったので紹介します。
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.ProtectionDomain;
import java.security.CodeSource;

public class ClassUtils {

public static URL findClassLocation(Class c)
throws SecurityException {
Package p = c.getPackage();
String className;
if (p != null) {
className = c.getName().substring(p.getName().length() + 1);
} else {
className = c.getName();
}
URL location = c.getResource(className + ".class");
if (location == null) {
// NOTE: 昔 Tomcat の WEB-INF/lib とかの jar を探すときはこの
// 処理に入ったのだが。。。今は不要かも。
ProtectionDomain domain = c.getProtectionDomain();
CodeSource source = domain.getCodeSource();
if (source != null) {
location = source.getLocation();
}
}
return location;
}

private static File findBaseDirectory(URL classLocation)
throws IOException {
if (classLocation == null) {
return null;
}
String file = classLocation.getFile();
if (classLocation.getProtocol().equals("jar")) {
int i = file.lastIndexOf('!');
if (i != -1) {
file = file.substring(0, i);
}
return findBaseDirectory(new URL(file));
}
File dir = new File(URLDecoder.decode(file,
System.getProperty("file.encoding")));
if (!dir.isDirectory()) {
dir = dir.getParentFile();
}
return dir;
}

public static File findBaseDirectory(Class c)
throws SecurityException, IOException {
return findBaseDirectory(findClassLocation(c));
}

public static void main(String[] args) throws Exception {
System.out.println(findBaseDirectory(java.lang.String.class));
}
}


これがあれば xxx.home などのシステムプロパティ渡さずに済むことが多々あると思います。
sen などもこれに対応してくれればなぁ。。。

2008年6月30日月曜日

プログラミングコードの貼り付け(2)

前記事:プログラミングコードの貼り付け
またまた Blogger の仕様が元に戻りました?今日確認したら pre の中に br が入らなくなったようなので、以下の CSS を取り除きました。
pre.code br {
display: none;
}

どうせやるなら以下のような書き方のほうが Blogger 云々に右往左往しなくて良かったかも。
pre.code br+br {
display: run-in;
}

2008年6月27日金曜日

Java めんどくさっ

先日 OpenIdea.jp というサービスを初めた記事を書きました。Java で出来ています。でも作ってる途中、感じました。。。

Java めんどくさっ

ちゃんと書くにはいい言語で、総合的には最も好きなんですが、何せ面倒くさい。

そんなとき以下の記事見つけました。
COBOL のように死んだ言語 ~ Java は置き換えられる時期に来ているのか

ふむ。なるほど。。。とりあえず Groovy はじめてみよう。

プログラミングコードの貼り付け

今日から Blogger の仕様変わりました?何故か pre で囲んでいたプログラミングコードが余計に改行されるようになったんで次の対策をとりました。

元々以下のような CSS を [レイアウト] - [HTML の編集] から仕込んで置いたのですが、
pre.code {
background: #eee;
border: 1px solid #ddd;
width: 95%;
padding: 5px;
font-size: 85%;
word-wrap: break-word; /* fix for long text breaking sidebar float in IE */
overflow: auto; /* fix for long non-text content breaking IE sidebar float */
}

この CSS を追加することで pre.code 中の br を無効にできました。良かった良かった。
pre.code br {
display: none;
}

参考にさせていただいたのは次の 2サイトです。
<br>の連打をuser CSSで無効にする。 - ま゚゚
pre 要素のスタイル定義とマークアップ

2008年6月30日 続きの記事へ

2008年6月26日木曜日

サーブレットコンテナ(Tomcat)とリバースプロクシを組み合わせた時の問題解決

Tomcat とリバースプロクシを組み合わせた時に微妙な問題に直面しました。その問題の解決方法をメモしておきます。

状況としては、Tomcat は http://localhost:8080/app/ のようにコンテキストパス /app で動作しています。
/app で動作しているアプリケーションに http://app.example.com/ という URL でリバースプロクシの設定を行います。
Tomcat は他のアプリケーションも動作しているので、ルートコンテキストは用いることができません。
http://app.example.com/ (Apache)

(リバースプロクシ)

http://localhost:8080/app/ (Tomcat)

まずはこんな感じで設定しました。問題は 2つあります。
ProxyPath / http://localhost:8080/app
ProxyPassReverse / http://localhost:8080/

1つ目は Cookie 問題です。Tomcat の発行する Set-Cookie の Path 属性が /app となり、ブラウザが / へのアクセスのときにはリクエストヘッダに Cookie をつけて送信しません。
Set-Cookie: JSESSIONID=XXXXXXXXXXXXX; Path=/app

ここでは、ProxyPassReverseCookiePath ディレクティブを用いて、Set-Cookie の Path属性 /app を / に置換します。
ProxyPath / http://localhost:8080/app/
ProxyPassReverse / http://localhost:8080/
ProxyPassReverseCookiePath /app /

これでブラウザへは次のヘッダが返されます。
Set-Cookie; JSESSIONID=XXXXXXXXXXXXX; Path=/

2つ目はコンテキストパス問題です。Tomcat をルートコンテキストで動かしたり、ルートコンテキストは他で使っていても、ポートを変えてもう 1つ Tomcat を起動すれば問題はすぐ解決するのですが、ここは敢えて別の方法をとってみます。

やりたいことは、次の 2つの URL どちらからアクセスしても同じように動くことです。
http://app.example.com/
http://localhost:8080/app/

今回は以下のような方法を使ってみました。

まず、リバースプロクシの設定に加え X-Context-Path という独自のヘッダを付与します。
RequestHeader set X-Context-Path ""
ProxyPath / http://localhost:8080/app/
ProxyPassReverse / http://localhost:8080/
ProxyPassReverseCookiePath /app /

これで Tomcat は、リバースプロクシからきたリクエストを X-Context-Path というヘッダで判断することができます。
次にサーブレットフィルタを作成し、リクエストオブジェクトをラップして、getContextPath メソッドをオーバーライドします。
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
doFilter((HttpServletRequest) req, (HttpServletResponse) res, chain);
}
public void doFilter(HttpServletRequest req, HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
// NOTE: X-Context-Path を受け取って、null で無ければその値を
// コンテキストパスとして使用する。
// ※実際は XSS などを埋め込まれないように文字列チェックする必要
// あります。
final String contextPath = req.getHeader("X-Context-Path");
if (contextPath != null) {
req = new HttpServletRequestWrapper(req) {
public String getContextPath() {
return contextPath;
}
};
}
chain.doFilter(req, res);
}

この他に getServerPort や getRequestURI など変更すべき箇所がたくさんありますが省略。。こうしておけば、http://localhost:8080/app/ にアクセスしたときも http://app.example.com/ にアクセスしたときも期待通りに動作します。

会社案内資料

今日、知り合いと一緒に他社をまわったときに気づきました。
わが社には会社案内資料がない。作らねば。。

2008年6月25日水曜日

OpenIdea.jp

OpenIdea.jp というサービスを作ってみました。

作った理由:
  • 日ごろ思いつくアイデアを公開したかった。(普段はメールの下書きでためていました。)
  • 何でも良いからサービスを 1つ公開したかった。
苦手な HTML コーディングや、ロゴなども自分でやってます。
Java、ClickFramework、DbUtils、MySQL などで動いてます。まだ検索やランキングも動いてなかったり。。

今のとこ、何ら新しいことはないのですが、実験場として色々追加していく予定です。

今後の予定:
  • アイデアグラフ(最初はツリー表示でいいかな)
  • OpenID 2.0 対応
  • メール投稿
まだプレスリリースとかしてません。もうちょっと触ったらやろうと思います。