タグ「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スコープから値を取得できます。

めでたし。めでたし。

JSPでEL式が使えない場合の対策

久々のblogネタを投稿してみる。

最近、JSPをよくいじっているわけですが、JSPにはJSTL(JSP Standard Tag Library)の標準タグライブラリとEL(Expression Language)式が使えると便利かなと思いました。

JSTLとは、JSPで使えるカスタムタグライブラリの一つで、JakartaプロジェクトによりJSPで便利なタグをひとまとめにしたライブラリです。
その中でよく使われるのがCoreタグライブラリとEL式です。

JSTLに関する詳しい解説はKishida's SITE 〜 Java入門講座 - JSTL(標準タグライブラリ)Javaの道(Java入門・リファレンス) - Javaの道:Taglibs(2.Standard Taglibsの概要)に丸投げしますが、今回はそのEL式が使えない場合のお話。

JSTLを使うには、JakartaプロジェクトのページからJSTLのファイルをダウンロードし、サーブレットコンテナ(Tomcat)のWEB-INF\libに「standard.jar」と「jstl.jar」を設置してやることで完了です
...って思ってたんですよ。

ええ、これだけでも<c:out>や<c:forEach>などのタグライブラリは動くんです。
でもね、でもね。
これだとEL式が動いてくれなかったんですねorz

${true}がそのまま「${true}」って表示されちゃうんです( ̄□ ̄;)!!

そこで色々ググってみたところ、似たような問題で悩んでいる方はいました。

wakasa.org - ●Tomcat5.5でtaglib内でEL式が動かない

ただ、俺の場合これだけじゃありませんでした。
「standard.jar」や「jstl.jar」を「WEB-INF\lib」に設置するだけではなく、「web.xml」にの設定も追加しましょう。

Tomcat5の新機能第2回:EL式とタグファイルに書かれていますが、

<taglib>
<taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tld/c.tld</taglib-location>
</taglib>

を忘れると、JSTLが使えるのにEL式が使えないという不思議な体験ができます。
結局のところ俺がきちんと説明書見てなかったからこんな事態になっただけなんですけどねorz

というわけで、自分の備忘録とともに同じ問題で苦しんでいる人の助けになれば良いかなと思います。

久々にblogを書く機会がバグへの対処とはorz

2006年08月27日に投稿した「sendRedirectで日本語文字のURLが入っている場合の対処」の記事の方法だとURLによりExceptionが発生してしまうようです。
URL中に半角スペースを含むURLの場合RFC2396に違反するため、エスケープしなければいけません。
実はJ2SDK 1.4までは半角スペースを含むURLであってもURIクラス等でインスタンスを作成可能でしたが、JDK 5.0からはRFC2396に従いあらかじめエスケープしなければいけなくなったようです。

String strUrl = "http://traincat.net/blog/neko/電車猫の blog/日本語 ファイル名.doc".replace(" ","%20");
URI uri = new URI(strUrl);
response.sendRedirect(uri.toASCIIString());

この様にすれば、半角スペースが「%20」と変換されるのでURISyntaxExceptionやMalformedURLExceptionなしにURIクラスのインスタンスを作成できそうです。

めでたしめでたし。


・参考文献:
SMG-Java トラブルシューティング
 + JDK1.3で動作していたプログラムをJDK1.4で実行したところ、Naming.bind()で例外が発生しました。