2007-12-29

"IE で SSL Web サイトの Office 文書を開けない" のを Apacheで何とかする

「このインターネットのサイトを開くことができませんでした。要求されたサイトが使用できないか、見つけることができません。後でやり直してください。」

HTTPS経由でOfficeの文書ファイルなどを開こうとすると、このようなエラーが出て開けないことがある。これはIEの仕様だそうだ。
Internet Explorer で SSL Web サイトの Office 文書を開けない

SSLで保護されたWebサーバから文書ファイルをダウンロードする際、レスポンス上の Pragmaや Cache-controlヘッダでキャッシュ抑制を要求している場合にこの問題が起こる。

キャッシュコントロールヘッダを出力しているのが何らかのサーバ側アプリケーションであれば、HTTPSの場合そのようなヘッダを出力しないといった処理を追加することで対処出来るだろうが、アプリケーションが改変不能な場合は最後の手段として Webサーバ側で強制的にヘッダを剥奪する。Apacheの場合、Headerディレクティブでそのような設定を出来る(要mod_headers)。
# SSLのvhost内にて
<Location /path/to/download>
Header unset Pragma
Header unset Cache-control
</Location>
この設定の影響範囲については各自で検討の上、副作用をもたらさないようにされたし。

Apache2.2の mod_proxyと mod_cacheであらゆるものをキャッシュする

mod_proxyとmod_cacheを使うと、Apacheをキャッシュプロキシとして使うことが出来る。これは広く知られている。

ところで、普通キャッシュプロキシは動的コンテンツをキャッシュしない。しかし、(ごくごくレアではあるが)キャッシュできるならとにかくなんでもキャッシュして欲しい場合もある。どんなケースか具体的には語らないが。

mod_cacheが何を持って動的コンテンツであるか(ひいては、キャッシュ対象としてふさわしいコンテンツであるか)判断しているかは mod_cacheのドキュメント(翻訳ではなく原文のほう)を参照するとして、手っ取り早く「貪欲キャッシュ」を実現するには下記のようなProxy設定にする。
ProxyRequests On
CacheRoot /var/cache/apache2
CacheEnable disk /
CacheIgnoreCacheControl On
CacheIgnoreNoLastMod On
CacheStoreNoStore On
CacheStorePrivate On

Header set Expires "Thu, 01 Jan 2099 00:00:00 GMT"
CacheRoot設定(キャッシュファイルを保存する場所)は各自の環境に合わせられたし。なおGentoo(Portage)でApacheをインストールした場合は /var/cache/apache2が自動的に作成されている。

重要なのは、Headerディレクティブ(要mod_headers)で Expiresヘッダを強制的につけることで、パラメータつきのGETリクエストに対するレスポンスもキャッシュ対象として認識させていることだ。このハックには計り知れない副作用が予想されるので、共用のWebサーバに決してそのままこの設定を適用しない(<directory proxy:*>で囲むなどする)よう注意されたい。

2007-12-25

Mac OS X 日本語ファイル名の合成文字とSubversion

Leopardのターミナル(や、シェルやvi)は日本語文字列の扱いがだいぶマシになったので、日本語名のファイルもコマンドラインのSubversionでやりとりしやすくなった。

しかし、
パーサ仕様.xls
をMac OS Xから Subversionリポジトリに投入すると、Windows側では
ハ□ーサ仕様.xls
のように化けてしまう。

Macのファイルシステムでは半濁点・濁点付きの日本語文字列をUNICODEの合成文字としてエンコードするのだが、Windowsはこういった合成文字をデコードすることが出来ないためそのような事が起こる。

どうしたものかと悩んでいたら、神のような人が居た。Subversion Precomposed UTF-8 patch
このパッチを当てたSubversionは、そういったファイル名に含まれる合成文字を Windowsでも読める普通の文字にPrecomposeしてリポジトリへ送信してくれる。

パッチされた Subversionのバイナリは普通にmake installすると /usr/local/bin/svn になるので、/usr/binよりも先に/usr/local/binへPATHを通すか、/usr/bin/svnを /usr/local/bin/svnのシンボリックリンクにすると良い。

2007-12-20

DNSのワイルドカード機能

DNSのワイルドカード機能を初めて使ってみた。

ワイルドカードに対してはDNSが no such nameを返さないため副作用的な問題が起こることを心得るべし、とのことだが webしか公開していない単機能なドメインだったら問題ないよね?

tekis.jp のパーソナルページ

Springのトランザクションマネージャを明示的に使う

Springの入門記事は大抵AOPでトランザクション境界を定義するやりかたを紹介している。それはそれでKeep POJOの観点から理想的なのだが、初心者は設定間違いなどにより実際にはトランザクション制御が効いていないようなケースでもそれに気付かず過ごしてしまうかもしれない。AOPを使わず明示的にトランザクション境界をコーディングしてみて、その後にAOPでの解決法へ移行する方がそういったミスを見過ごすことがないという意味では入門に適していると思う。
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);

try {
// ここでトランザクションの中身を実行
transactionManager.commit(status);
}
finally {
if (!status.isCompleted()) transactionManager.rollback();
}
transactionManagerは PlatFormTransactionManager(実体は DataSourceTransactionManagerなど)で、これは Spring Framework独自のトランザクションマネージャである(JEEのトランザクション管理機構を使いたい場合はこのトランザクションマネージャでラップして使う)ため、これを明示的に使用したコードは Springに依存することになる。

注意しておかなくてはならないのは、データベースアクセスを伴う処理を Springのトランザクションマネージャによるトランザクション制御の影響下に収めるためには守らなければならない約束事があるということだ。それは、少なくとも下記のうちいずれかの方法でデータベースへアクセスすることである。

・dataSource.getConnection() のかわりに、 DataSourceUtil.getConnection(dataSource) でJDBCコネクションを得る。コードはSpring依存になる。
・全てのSQLを JdbcTemplate クラス経由で実行する。コードは Spring依存になる。
・DataSourceオブジェクトを TransactionAwareDataSourceProxy で包んでおき、それに対して getConnection() が行われるようにする。

後々 Keep POJOでAOPなトランザクション制御へ移行する予定なら最後の方法を使うと良い。

ラベル:

2007-12-09

iPod touch用に作った動画を Flash Playerで再生する

2007年12月初頭にリリースされた最新の Flash Player 9(Update3)では、H.264コーデックが組み込まれ、かつ QuickTimeや MPEG-4など FLV以外のコンテナフォーマットにも対応となった。というわけで、同じくH.264を採用している iPod touch用に今まで蓄積した動画ファイル(.mp4)を再生出来るかどうか Flexの VideoDisplayコンポーネントで実験してみることにした。

結果、再生は出来たものの「動画ファイルのダウンロードが最後まで終わってから再生開始」という動作になってしまった。つまり、プログレッシブにダウンロードしつつ再生することが出来ない。

(なお、iPod用の動画ファイルを作成するのには elgato turbo.264 を使っている)

どうやら何らかの情報がストリーミング向けに都合の良い形で格納されていないといけないようだ。

そこで、GPAC という MPEG4操作用フレームワークに収録されている MP4Box というコマンドラインツールでそこらへんを修正できそうだったので、試してみた。

MP4Box -ocr -iod -inter 1 myfavoritemovie.mp4

一瞬で処理は終わり、修正された MP4ファイルを Flash Playerに再生させてみたところ期待通りプログレッシブに再生が行われた。いと うれし。

今までだと、趣味(私の場合スキューバダイビング)の動画を人に見せる際は

Windowsの人はQuickTimeをインストールしてね(iTunesに含まれているよ!)

とか、

Windowsの人はこちら→(WMV版へのリンク) Windows以外の人はこちら→(MPEG-4版へのリンク)

のように面倒なナビゲーションをしなければならなかった。

しかし今後は一貫して「Flash Playerを最新版に更新してね!」で済むようになったのが有り難い。アドビ万歳!でもマクロメディアを買収することで得た独占支配力は、ユーザーやベンダから金を巻き上げるためではなくマイクロソフトに対抗するために使って頂きたいところ。

2007-12-07

Spring 2.5 MVC コントローラ アノテーション

あまり話題になることのない Spring MVCだが、私は「DIが可能でちょっと便利なサーブレット」として使うことがある。Spring 2.5では、アノテーションでコントローラクラスの使われ方を設定できるようになり楽になったので情報をメモしておく。

参考: 13.12. Annotation-based controller configuration

web.xmlの設定

Spring 2.0の時と同じで、DispatcherServletをservlet登録し、URIにマッピングする。ただし Spring 2.5の配布では、DispatcherServletは spring.jarに入っておらず spring-webmvc.jarに収録されているため、spring.jarの他に spring-webmvc.jarもプロジェクトに加えること。

<?xml version="1.0"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
version=
"2.4">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>hello/*</url-pattern>
</servlet-mapping>
</web-app>
WEB-INF直下には、servlet-name要素で指定したサーブレット名の後ろに-servlet.xml を付けた名前で Springのbean定義ファイルを配置する。これも Spring 2.0と同様。

アノテーションで設定をする場合、コントローラは bean要素でただロードさせるだけで良い。

<bean class="com.acme.hello.web.HelloController" />

また、「このパッケージ以下にあるコントローラクラスを全部」のような指定もできる。
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
...
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
..."
:
<context:component-scan base-package="com.acme.hello.web" />
:
context:component-scan要素は base-packageで指定されたパッケージ以下に存在する @ComponentアノテーションのついたクラスをsingletonなBeanとして自動的に登録してくれる。(後述する @Controllerは @Componentの特殊化)

コントローラクラスには @Controllerアノテーション(org.springframework.stereotype.Controller)をつけてやる。
@Controller
public class HelloController {
:
}
URIに処理をマッピングするには、@RequestMappingアノテーションを使う。
1種類のURIに1個のコントローラを割り当てる場合はコントローラクラスに、1個のコントローラで様々なURIの処理を行うにはコントローラクラスのpublicメソッドにそれぞれ @ResultMappingアノテーションでURIを指定する。ここでは後者を例にとる。

@RequestMapping("/hello.do")
public String hello() throws Exception
{
return "hello.jsp"; // hello.jspへ処理を渡す
}
リクエスト毎にインスタンスの生成される Struts2(aka WebWork)のActionクラスと違い、Spring MVCのコントローラクラスはシングルトンなので、リクエストパラメータやビュー層へ渡す値についてはメソッドの引数を使う。メソッドの引数とリクエストパラメータの対応付けもアノテーションで指定できる。また、引数に Mapがあるとそこにはビューに渡す値のマップとして使える Mapのインスタンスが渡される。

public String hello(@RequestParam("name") String name, Map results)
{
results.put("message", "Hello, " + name + "!");
return "hello.jsp";
}
他にも
HttpServletRequest(IN)
HttpServletResponse(OUT)
org.springframework.web.context.request.WebRequest (IN)
java.util.Locale (IN)
java.io.InputStream(java.io.Reader) (IN)
java.io.OutputStream(java.io.Writer) (OUT)
org.springframework.ui.ModelMap (OUT)
などをメソッドの引数に含めることが出来る。

HTTPリクエストに対しバイトストリームをレスポンスしたい場合 OutputStreamを引数に含めておけばそれを使うことが出来るが、content-typeや content-lengthをセットできないためいくつかのケースでは実用的ではないかもしれない。そのような場合、代わりに HttpServletResponseを使うことになると思う。

■おまけ■

Spring 2.5では、プライベートフィールドに @Resourceアノテーションをつけると setterメソッドが無くても beanを autowireしてくれる。(Resourceアノテーションは JEEのものなので、Java SEベースの環境であれば Springの配布に含まれる lib/j2ee/common-annotations.jar をクラスパスに追加すること)

@Resource private DataSource dataSource;
@Resource private PlatformTransactionManager transactionManager;

setterメソッド(フィールドに値を代入するコード)が無いためコンパイラが警告を出すが・・・。

ラベル:

2007-12-04

64bit Windowsで 32bitのODBCドライバを使う

RDBMSにアクセスするためODBCドライバをインストールしたが、データソースを設定すべくコントロールパネル→管理ツール→ODBC を開いてもドライバ一覧に出てこない・・・64bit Windowsを使っているとそういうことが起こる。理由は簡単で、インストールしたODBCドライバが64bit版じゃないから。

そういう時は 32bit版の ODBCアドミニストレータを実行してやると良い。
C:\WINDOWS\SysWOW64\odbcad32.exe

これで設定すれば、32bitアプリケーションからODBCデータソースを利用できる。

Linux上の Java 1.4で、AWT関係が動作しない

イメージング関係のライブラリでは後ろでAWTを使っていることが多い。そのため X Window Systemを入れていないLinux環境だと動作しないことがある。
そのような場合、VMのオプションとして -Djava.awt.headless=true を付けると Xサーバのインスタンスが不要になるため問題は解決する。ように思えたが、Java 1.4のAWTは libXp.soなる deprecatedなX関係のライブラリに依存しているため、最近の Linuxディストリビューションでは NoClassDefFoundErrorになってしまい動作しないという問題が発生してしまう。

「headless指定をすればXがいらない」という思いこみのため、この問題の追跡には時間を要してしまった。

なおJava 5以降の libawt.soをlddしてみたところそういう依存関係自体が解消されているようだったので、これは Java1.4特有の問題と思われる。

VMを Java5以降にスイッチするか、libXp.soをインストールすることでこの問題を回避できるだろう。
CentOSの場合、yum install xorg-x11-deprecated-libs で libXp.soが入る。

2007-12-03

CentOS 5.1 Released

DVDイメージは BitTorrentで取得するのが良い。
http://ftp.kddilabs.jp/Linux/distributions/CentOS/5.1/isos/x86_64/CentOS-5.1-x86_64-bin-DVD.torrent

Mac(など)用 BitTorrentクライアント Transmission