「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」のようなファイルが出力されるようになります。

めでたしめでたし。

iTextを用いてJava ServletからPDFを作成する

現在JSP & Java Servletを用いてWebアプリケーションを開発していますが、PDFの帳票出力が必要になりました。色々調べてみると、JavaプログラムからPDFを出力するためのライブラリが無料で公開されており、意外に簡単にできそうなのです。

CodeZine - iTextを利用してJavaからPDF形式の帳票を出力する
※会員登録することで、iTextを用いたサンプルWebプログラムをダウンロードすることができます。

サイト内のソース解説を見ていただければお分かりの通り、カプセル化のカプセル化で作成する形なので、オブジェクト指向が分かる方には(もしかしたらそうでない方も含め)コーディングしやすいのかななんて感じます。

PDFの中に自分の名前が入るとかたまらないですね(≧∇≦)(何)


解説するもの全て上記サイトで解説されつくしている感じなので、今回はiTextのサンプルプログラムをEclipseに読み込ませようとしたときのトラブルについて対処法を記述しておきます。

Eclipseのワークスペースに、展開したiTextのサンプルプログラムを配置したところ、正しく動作しませんでした。

Unable to find a javac compiler;
com.sun.tools.javac.Main is not on the classpath.
Perhaps JAVA_HOME does not point to the JDK
みたいなエラーがでたので、ググってみたところ、同様の症状が出た場合の対処法が書かれているサイトを見つけました。

Eclipse 3.2 日本語版の場合、[ウインドウ(W)]→[設定(P)...]→[Tomcat]→[JVM設定]の「クラスパス (生成されたクラスパスの前)」で[Jar/Zip]ボタンをクリックし、「%JAVA_HOME%\\lib\tools.jar」のライブラリを追加してください。
※「%JAVA_HOME%」はJDK 5.0、または、J2SDK 1.4をインストールしたトップフォルダのことです。

サンプルプログラムなのに、ソースを確認したら赤字だらけだって方は、Eclipseを起動すると左側に位置する[パッケージ・エクスプローラー]に存在すると思います。iTextのアプリケーションフォルダを右クリックし、[プロパティ(R)]→[Java のビルドパス]→[ライブラリー(L)]タブを開きます。[JAR の追加(J)...]で、「(iTextのサンプルプログラム)\WEB-INF\lib」の下にある「itext-1.3.jar」と「iText-Asian.jar」を選択し、[OK]ボタンをクリックします。
パッケージ・エクスプローラーのiTextフォルダに先ほどクリックした2つのファイルが表示されれば、赤字だったソースの箇所が消えていると思います。

こんな感じでJavaからPDFを作成してみましょ〜。

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
それでも解決できて何よりでした。

相変わらず放置具合が素敵な感じになっていますが、それでもブログ運営を続けます(≧∇≦)
サンプルが書かれているサイトを参考に製作していたため、思わぬ落とし穴に気付かなかった話でも書いてみようかと思います。

Struts+HibernateのWebアプリケーションを製作していたら、データベースに接続するページがやけに遅い気がしました。そこで、実際にLog4Jを用いて計測してみたところ、データベースの接続(Hibernateのセッション接続)のところで0.5秒前後掛かってました。
これはいくらなんでも掛かりすぎだろ...

データベースのコネクションプールが問題なのかと思い、hibernate.cfg.xmlのhibernate.connection.pool_sizeの値を変更してみましたが、状況としては全く変わらずorz

しかし、調べてみると原因は思わぬところにありました。
例えば、何かの情報について検索するDAOに以下のようなメソッドを作成するとします。

public List searchAll() {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
// 罠にはまった壁
List list = session.createCriteria(クラス名.class).list();
return list;
}
よくHibernateのサンプルを公開しているHibernate初心者向けサイトに行くと、メソッドごとに「//罠にはまった壁」から上の3行が書かれています。それが問題でした。 上の3行をメソッドごとに記述してしまうと、コネクションプールが設定されていたとしても、それを切断して新たなコネクションプールを作成してしまいます。コネクションプールを用いて接続までの時間を短縮させる設定が全く活かされなかったんですね。

ではどうするかと言いますと、「//罠にはまった壁」の上3行のうち、上位2行をプラグインとしてTomcat起動前に読み込ませる必要があります。

package hibernate;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class SamplePlugIn implements PlugIn {

public void init(ActionServlet servlet, ModuleConfig config)
throws ServletException {
// Webアプリケーションの開始処理
System.out.println("*** SamplePlugIn initメソッド 起動 ***");

// Hibernateのセッションを取得
Configuration hibernateConfig = new Configuration().configure();
SessionFactory sessionFactory = hibernateConfig.buildSessionFactory();

// メッセージをServletContextに保存
ServletContext context = servlet.getServletContext();
context.setAttribute("sessionFactory", sessionFactory);

System.out.println("*** SamplePlugIn initメソッド 終了 ***");
}

public void destroy() {
// Webアプリケーションの終了処理
System.out.println("*** SamplePlugIn destory()メソッド ***");
}
}


次に、DAOやStrutsのActionクラス内でServletContext(Appilcationスコープ)に格納した「sessionFactory」を取得し、セッションを作成します。

ServletContext context = servlet.getServletContext(); Session session = context.getAttribute("sessionFactory").openSession();
その後は、Hibernateによりデータベースの処理を記述するだけです。

これでHibernateに0.05〜0.1秒で接続するようになり、体感的に遅く感じなくなりました。

※上の例ではアプリケーションスコープに格納する方法を採用しましたが、init()メソッドにSessionFactoryの作成までを行うstaticメソッドを作成し、同様にHibernateのセッションを静的メソッドで行う方法もあるようです。
そんなわけで、めでたしめでたしということで。

※StrutsのActionでHiberateのセッションを取得したい方は、StrutsからServletContextクラスを取得するにはも参考にどうぞ。