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 対応
  • メール投稿
まだプレスリリースとかしてません。もうちょっと触ったらやろうと思います。

2008年6月4日水曜日

memcached でキーの列挙(2)

前回(memcached でキーの列挙)の続きです。サンプルの Perl コードです。ちょこっといじればイベント駆動のモジュールが作れそう。。

my $size = 1000;
my $cache = Cache::Memcached->new({
servers => ['localhost:11211'],
});
my $slabs = $cache->stats('slabs');
my @stat_ids = ();
for my $host (keys %{$slabs->{hosts}}) {
my $slabs_text = $slabs->{hosts}->{$host}->{slabs};
my @lines = split("\n", $slabs_text);
for my $line (@lines) {
($line =~ /STAT ([0-9]+):chunk_size [0-9]+/) or next;
push(@stat_ids, $1);
}
}
for my $stat_id (@stat_ids) {
my $cmd = "cachedump $stat_id $size";
print "[$cmd]\n";
my $cachedump = $cache->stats($cmd);
for my $host (keys %{$cachedump->{hosts}}) {
my $cachedump_text = $cachedump->{hosts}->{$host}->{$cmd};
my @lines = split("\n", $cachedump_text);
for my $line (@lines) {
($line =~ /^ITEM (.+) \[(.+) b; (.+) s\]/) or next;
my ($key, $b, $s) = ($1, $2, $3);
print "\t$key [$b bytes]\n";
}
}
}

2008年6月3日火曜日

memcached でキーの列挙

memcached で、キーの列挙ができないか調査していたところ、PHPで実現している方のブログ記事を見つけました。( http://blog.cles.jp/item/2141 )

これ Perl の Cache::Memcached でできるだろうと思って挑戦したのですが、何故か stats cachedump が動作しないんです。

そこで telnet を使って直接コマンドをたたいてみることにしました。まずは接続。。
> telnet localhost 11211

次に stats slabs コマンドを実行してみます。
stats slabs
STAT 1:chunk_size 80
STAT 1:chunks_per_page 13107
STAT 1:total_pages 1
STAT 1:total_chunks 13107
STAT 1:used_chunks 13107
STAT 1:free_chunks 0
STAT 1:free_chunks_end 13065
STAT 2:chunk_size 100
STAT 2:chunks_per_page 10485
STAT 2:total_pages 1
STAT 2:total_chunks 10485
STAT 2:used_chunks 10485
STAT 2:free_chunks 0
STAT 2:free_chunks_end 10447
.....
STAT active_slabs 16
STAT total_malloced 16763844
END

この出力結果のうちの STAT {数字} の部分を使って stats cachedump コマンドを実行します。STAT {数字} は連番ではないみたいなので注意が必要です。
stats cachedump {数字} {ダンプするキーの最大数}
ITEM {キー} [{統計情報}]
.....
END

おお。キーの列挙できるじゃん。ちゅうことで Cache::Memcached のソースみたら stats メソッドは引数を最初の 1個しか使ってないのか。
# 中身も見ずにこういう呼び出しをしてしまってた。
$cache->stats('cachedump', 1, 100);

# こうすりゃ良かったんすね。
$cache->stats('cachedump 1 100');

memcached でキーの列挙(2)へ続く