タグ「Tomcat」が付けられているもの

OASでLog4Jが原因のデプロイエラーが発生する

OAS(Oracle Application Server)に、WARファイルをデプロイしようとしたところ以下のエラーが発生し、失敗しました:
Operation failed with error: org/apache/log4j/Category 

今回作成しようとするシステムの中には確かにLog4Jのログ出力が含まれている訳ですが、それが原因で失敗してしまったら、実に困りものな訳ですね。
デプロイ時の設定に問題があると思いまして調査したところ、やっぱりデプロイ時のOASの共有ライブラリの設定に問題がありました。

共有ライブラリのインポート設定で[apache.commons.logging]のチェックボックスを外しましょう。
OASの共有ライブラリのインポート設定って結構くせ者ですよね...
しかも、Oracle製品だけあって相変わらず情報が少ない(;_;)

同様の悩みを抱えている方も、この情報が役に立つことを祈ってます( ̄∇ ̄)ノ♪

Apache Tomcatでアクセスログを出力する

Apache TomcatではWebページへのアクセスログが出力はできません。つまりどのファイルにアクセスされたとか、404エラーが発生しているパスとかの調査はできません。

...ってそう思っていた時代が俺にもありました。
マジで、かれこれ4年間本当にそう思っていましたorz

JSP & Servletコンテナだから仕方ないと思っていたのですが、最近、アクセスログ用いて調査しなくてはいけない懸案が発生したので、Google大先生に聞いてみました。
そしたら普通にあるじゃんorz

"(Tomcatのインストールフォルダ)\conf\"に存在するserver.xmlを開きます。

現在、私がインストールしているバージョンでは、341行目〜345行目に以下のような記述がされています。

<!-- <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/> -->

ご覧の通り、デフォルトではコメントアウトされていますのでコメントアウト部分の「<!--」と「-->」をさくっと削除してしまいましょう。

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>

すっきり!(某番組風)

このように設定した後、Tomcatを再起動すれば、"(Tomcatのインストールフォルダ)\logs"に「localhost_access_log.2008-06-21.txt」のようなファイルが出力されるようになります。

めでたしめでたし。

Apache Tomcatで動作したWebアプリケーションをOracle Application Server(OAS)で動作させようとしたら正常に動作しなかった問題とその解決法について紹介します。

事の発端は以下の通り:
Eclipse+Tomcatで製作したWebアプリケーションを、一度、WARファイルに固めました。
そして、OASに配置して動作試験を行いました。
しかし、EL(Expression Language)を使用しているページで式言語がそのままの文字で出力されてしまう問題が発生しました。

JSPでEL式が使えない場合の対策で書いたことを疑いましたが、そもそもWARファイルに固めているのでライブラリも含まれています。

なんだかんだで必死に原因を調べたのですが、思わぬところに理由がありました。

@ITのJ2EE 1.4に対応したweb.xmlを記述するの記事に、J2EE 1.3とJ2EE 1.4の場合のweb.xmlが書かれています。

J2EE 1.3の場合のweb.xmlは

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
  ...中略...
</web-app>

J2EE 1.4の場合のweb.xmlは

<?xml version="1.0" encoding="UTF-8"?>
<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">

  ...中略...
</web-app>

となっています。

問題のWebアプリのweb.xmlは以下のようになっていました:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<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">

  ...中略...
</web-app>

もうお分かりですね、J2EE 1.3の設定とJ2EE 1.4の設定が混ざっていたんですorz

今回の原因を考察してみました。
今回Apache TomcatはVer5.0.24を使用しておりJ2EE 1.4に準拠すること前提で製作されているため元々EL式を読み込むようになっているようです。対して、OASの方はWebサーバこそApache Web Serverのソースを流用していますが、Servletコンテナはそうではないようです。そのため、Apache Tomcatより厳密にweb.xmlを解釈しているものと思われます。
<web-app>タグより前に存在するDOCTYPE宣言を見た上で、J2EE 1.3のアプリケーションと認識してしまったようですね。

説明し忘れましたが、EL式(式言語)がデフォルトで対応になったのはJ2EE 1.4からです。それ以前のバージョンはJSTL(JSP Standard Tag Library)のライブラリとweb.xmlの設定をして初めて対応になります。

OASではELは動作する情報しか出てこない中、OASの情報がそもそも少ないので今回の原因調査には何日も掛かってしまいましたorz
それでも解決できて何よりでした。

Apache Tomcat 5.0.28+Strutsを使用しているとちょっと困った症状に出会いました。

StrutsのActionサーブレットでHttpServletRequest#getSession(false)のメソッドを用いても、新しいセッションを取得してしまうようです。ちょっとググってみると、Strutsでではないのですが、同様の問題で悩んでいる人がSeasarのMLでもいる模様です。

例えば、

HttpSession session = reqest.getSession(false);
if(session == null) {
// セッションタイムアウトのときの処理
}
を期待して、コーディングするとセッション切れのときは新しいセッションが作られてしまいセッションタイムアウトのときの処理が実行されません。

これを回避するには、あらかじめsessionに何かのオブジェクトを格納しておく方法をとると良さそうです。

例えば、ログインのActionServletにおいて

HttpSession session = req.getSession(true);
session.setAttribute("hoge","何かの文字列");
としておき、ログイン以外のServletにおいては、
HttpSession session = req.getSession(false);
if( (session == null) || (session.getAttribute("hoge") == null) ) {
// セッションタイムアウトのときの処理
}
とすると、新しいセッションが作成されたときに、HttpSession#getAttribute("hoge")がnullにならないのはログイン用のサーブレットを実行し、セッションタイムアウトしていない場合に限定されるので、うまく動作してくれます。

でも、状況的にApache Tomcat 5.0.28のバグの可能性が高そうだなぁ...


Strutsとセッションの話題をしたので、ついでにもう一つ良さそうな話題を紹介します。

@IT - 第4回 安全なセッション管理を実現するために
ここで公開されている内容は、Strutsのログインシステムを作る上で結構役に立ちそうです。
あるユーザでログイン後、セッションが切れる前にブラウザのログインページに戻って別のユーザでログインすると、前のユーザのログイン情報が残って危険な場合も考えられます。そのような問題も防げそうですね。
向こうの記事で十分説明されているので、敢えてこちらは講評だけにしておきます。

StrutsからServletContextクラスを取得するには

MVCモデルで知られているJSP&ServletのStrutsフレームワークですが、Contorollerの部分にあたるActionを作成しているときにちと困ったことになりました。
普通のサーブレットの場合、サーブレットの中でServletContextを呼び出すには、

ServletContext sc = getServletContext();

で良いわけですが、Strutsの場合は上記のような構文をexecuteメソッドの中に記述しても動きません。
せっかくStrutsのプラグインを用いてあるクラスをアプリケーションスコープに格納したのに取得できないなんてかなりorzな訳ですが。

ググってみたところ、上記のコードにもうひと味付けることで解決できました。

ServletContext sc = getServlet().getServletContext();
Foo bar = (Foo)sc.getAttribute("bar");

例えば、上記のコードのようにすれば、StrutsのActionサーブレットにおいてもApplicationスコープから値を取得できます。

めでたし。めでたし。