Oracle Containers for J2EE サーブレット開発者ガイド 10g(10.1.3.1.0) B31859-01 |
|
この章では、OC4JおよびOracle Application Serverのサーブレット開発に関する基本情報を説明します。次の項が含まれます。
OC4J開発に関するより一般的な情報については、『Oracle Containers for J2EE開発者ガイド』を参照してください。
注意
指定されたディレクトリでのサーブレット・ソースの自動再コンパイルをトリガーする、開発時に使用できる便利なフラグがあります。ソース・ファイルが前回のリクエスト以降に変更されていると、次のリクエスト時に、OC4Jによってサーブレットが再コンパイルされ、Webアプリケーションが再デプロイされ、サーブレットとすべての依存クラスがリロードされます。 |
HTTPサーブレットは、標準フォームに従って作成されます。HTTPサーブレットは、javax.servlet.http.HttpServlet
クラスを拡張するパブリック・クラスとして記述されます。ほとんどのサーブレットは、HTTPのGET
またはPOST
リクエストを処理するために、HttpServlet
のdoGet()
メソッドまたはdoPost()
メソッドをそれぞれオーバーライドします。コンテナがサーブレットをロードするときの初期化作業や、コンテナがサーブレットをシャットダウンするときのファイナライズ作業に特別な処理が必要な場合は、init()
メソッドとdestroy()
メソッドをオーバーライドすることもあります。
次の項では、これらのメソッドを実装する基本使用例を説明し、レスポンスの設定方法を示し、「Hello World」サーブレットのコードを順番に説明します。
次に、サーブレット開発の基本コード・テンプレートを示します。
package ...; import ...; public class MyServlet extends HttpServlet { public void init(ServletConfig config) { } public void doGet(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public void doPost(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public void doPut(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public void doDelete(HttpServletRequest request, HttpServletResponse) throws ServletException, IOException { } public String getServletInfo() { return "Some information about the servlet."; } public void destroy() { } }
次の項では、これらのメソッドをオーバーライドする例について説明します。
サーブレットの存続期間中に1回のみ必要となる特別な処理を実行するために、init()
メソッドをオーバーライドすることができます。次のような処理が含まれます。
たとえば、データソースを使用してデータベース接続を確立するには、次のようにします。
public void init() throws ServletException { try { InitialContext ic = new InitialContext(); // JNDI initial context ds = (DataSource) ic.lookup("jdbc/OracleDS"); // JNDI lookup conn = ds.getConnection(); // database connection through data source } ... }
ほとんどすべてのサーブレットは、大部分の処理について、HTTPのGET
リクエストを処理するためにdoGet()
メソッドを、またはHTTPのPOST
リクエストを処理するためにdoPost()
メソッドをオーバーライドします。GET
とPOST
は、フォーム・データをサーバーに渡すための2つのHTTPメソッドです。どのような場面でどちらのメソッドを使用するのかについて、このマニュアルでは詳しく説明しませんが、セキュリティを特に考慮する場合は、doPost()
メソッドの方が適していることがあります。これは、GET
メソッドでは、フォーム・パラメータがURL文字列に直接入力されたり、大きなデータ・シーケンスについて、クライアントがサーバーに送信できるデータの大きさが制限されなかったりするためです。
doGet()
またはdoPost()
の実装では、クライアントに渡すデータを生成するコードの作成に加えて、通常、HTTPリクエストからデータを読み取り、HTTPレスポンスを設定し、レスポンスを生成するコードを作成します。 追加情報は、この少し後にある「レスポンスの設定」および「HTMLフォームおよびリクエスト・パラメータの使用方法」を参照してください。
「単純なサーブレットの作成手順」に、簡単なdoGet()
実装の手順が示されています。
このメソッドを使用して、HTTP PUT
リクエストを実行します。これにより、ファイルがクライアントからサーバーに書き込まれます。doPut()
メソッドは、コンテンツ・ヘッダーを処理できる必要があります(処理できない場合はエラー・メッセージが生成されます)。また、受け取ったコンテンツ・ヘッダーに変更を加えないようにする必要があります。
このメソッドを使用して、HTTP DELETE
リクエストを実行します。これにより、ファイルまたはWebページがサーバーから削除されます。
このメソッドを使用して、サーブレットから、作成者やバージョンなどの情報を取得します。デフォルトでは、このメソッドは空の文字列を返します。このため、このメソッドをオーバーライドして、意味のある情報を提供する必要があります。
このメソッドは、サーブレットがシャットダウンされる直前にサーブレット・コンテナによってコールされます。次のように、サーブレットがシャットダウンの前にクリーンアップを必要とする場合は、このメソッドをオーバーライドすることができます。
たとえば、「init()メソッドをオーバーライドする場面」で開いたデータベース接続を閉じるには、次のようにします。
public void destroy() { try { conn.close(); } ... }
サーブレットからレスポンスを送信するには、使用しているサーブレット・メソッド(通常、doGet()
またはdoPost()
)に渡されるHttpServletResponse
インスタンスを使用します。主な手順は、次のとおりです。
OC4Jのデフォルト・コンテンツ・タイプが存在する場合は、OC4Jの
注意
global-web-application.xml
(グローバル)またはorion-web.xml
(アプリケーション・レベル)Webアプリケーション構成ファイルの<default-mime-type>
要素に反映されます。 このコンテンツ・タイプは、Application Server Controlコンソールのデプロイ・プラン・エディタ(概要は、「OC4J管理の概要」を参照)を使用して設定できます。
java.io.PrintWriter
)、バイナリ・データの場合は出力ストリーム(javax.servet.ServletOutputStream
)をレスポンス・オブジェクトから取得します。
次に、これらの手順に対応するコードを示します。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><body><h1>Hello World</h1></body></html>"); ... }
レスポンス・メソッドの要約は、「HttpServletResponseインタフェースの主要メソッド」を参照してください。
この項では、doGet()
メソッドをオーバーライドする「Hello World」の例を示します。 このサーブレットの全体は「単純なサーブレットの例」に示されていますが、この項でも順番に説明します。
サーブレットの例の最初の手順は、次のとおりです。
mytest
を宣言します。
package mytest;
import java.io.*; import javax.servlet.*; import javax.servlet.http.*;
HttpServlet
を常に拡張するサーブレット・クラスを宣言します。
public class HelloWorld extends HttpServlet { ... }
doGet()
をオーバーライドします。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ... }
サーブレットの例のdoGet()
メソッドの手順は、次のとおりです。
response.setContentType("text/html");
オプションで、文字コード(次の例のUTF-8など)を指定することもできます。
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html>"); out.println("<head>"); out.println("<title>Hello World!</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hi Amy!</h1>"); out.println("</body>"); out.println("</html>");
out.close();
(この単純な例では、リクエスト・データの操作は不要です。)
この項では、前の項で手順を順番に説明した単純なサーブレットの例の全体を示します。 この例は、「単純なサーブレットの例のデプロイおよび起動」でデプロイされ、起動されます。
次のコードを実行すると、ブラウザに「Hi Amy!」と表示されます。コードは、HelloWorld.java
というファイルに入力します。package
文に従って、HelloWorld
クラスはmytest
パッケージに含まれます。
package mytest; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWorld extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Hello World!</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hi Amy!</h1>"); out.println("</body>"); out.println("</html>"); out.close(); } }
サンプル・コードをコンパイルします。Sun社のJDKとそのデフォルト・コンパイラを使用している場合は、次のように、.java
ファイルのあるディレクトリからコンパイルします(%
はシステム・プロンプトです)。
% javac HelloWorld.java
一般的なサーブレットは、表示または操作するサーブレットの情報の入力をユーザーに求めます。サーブレットは、HTMLフォームを使用して情報を取得し、その情報をHTTPリクエスト・オブジェクトのパラメータに保存し、その情報をサーバーに送信することができます。または、リクエスト・オブジェクトからその他の情報(使用されているプロトコル、HTTPメソッド、リクエストURIなど)を取得することもできます。
次の各項で、いくつかの例を示します。
HTTPリクエスト・パラメータは、静的リソース(たとえば、.html
ファイルなど)へのリクエストのディスパッチ前に実行することになっているサーブレット・フィルタでは使用できません。 サーブレットまたはJSPページのような動的リソースの前に実行するフィルタからは、パラメータにアクセスが可能です。
リクエスト・メソッドの要約は、「HttpServletRequestインタフェースの主要メソッド」を参照してください。
サーブレットは、HTMLフォームを使用してユーザーから入力を取得し、これらのデータをHTTPリクエスト・オブジェクトのパラメータとしてサーバーに送信することができます。次に例を示します。
PrintWriter out = response.getWriter(); ... out.print("<form action=\""); out.print("RequestParamExample\" "); out.println("method=GET>"); out.println("Enter a new first name: "); out.println("<input type=text size=20 name=firstname>"); out.println("<br>"); out.println("Enter a new last name: "); out.println("<input type=text size=20 name=lastname>"); out.println("<br>" + "<br>"); out.println("<input type=submit>"); out.println("</form>");
この例では、ユーザーが名前と名字を入力するように求められ、名前はfirstname
というリクエスト・パラメータに、名字はlastname
というリクエスト・パラメータにそれぞれ格納されます。リクエスト・オブジェクトはサーバーに送信され、必要に応じてその情報がサーバーで処理されます(次の項を参照)。
ただし、この操作にGET
メソッドを使用することの重大な短所は、パラメータ名および値がサーブレットURL文字列に追加されることです。 これを避けるために、「URLセキュリティのためのPOSTメソッドの使用」で示すように、かわりにPOST
メソッドを使用することができます。
この項では、HTMLフォームを使用してユーザーが指定したリクエスト・パラメータ・データ(前の項を参照)を表示するサンプル・コードを示します。
PrintWriter out = response.getWriter(); ... String firstName = request.getParameter("firstname"); String lastName = request.getParameter("lastname"); out.println("First and last name from request:" + "<br>" + "<br>"); if (firstName != null || lastName != null) { out.println("First name "); out.println(" = " + firstName + "<br>"); out.println("Last name "); out.println(" = " + lastName + "<br>"); } else { out.println("(No names entered. Please enter first and last name.)"); }
リクエスト・パラメータのfirstname
とlastname
の値は、文字列のfirstName
とlastName
に格納され、ユーザーに出力されます。
この項では、これまでの項で説明したコードからなるサーブレットの全体を示します。このサーブレットは、ユーザーに名前と名字の入力を求め、その情報はリクエスト・オブジェクトに書き込まれます。サーブレットは、リクエスト・オブジェクトから名前と名字を取得して、ユーザーに出力します。(出力コードが最初に実行されます。このコードは、ユーザーが最初に名前や名字を入力するまで、名前が入力されていないことを示す「No names entered」というメッセージを表示します。)
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestParamExample extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Parameter Example" + "</h3>"); String firstName = request.getParameter("firstname"); String lastName = request.getParameter("lastname"); out.println("First and last name from request:" + "<br>" + "<br>"); if (firstName != null || lastName != null) { out.println("First name "); out.println(" = " + firstName + "<br>"); out.println("Last name "); out.println(" = " + lastName + "<br>"); } else { out.println("(No names entered. Please enter first and last name.)"); } out.println("<P>"); out.print("<form action=\""); out.print("RequestParamExample\" "); out.println("method=GET>"); out.println("Enter a new first name: "); out.println("<input type=text size=20 name=firstname>"); out.println("<br>"); out.println("Enter a new last name: "); out.println("<input type=text size=20 name=lastname>"); out.println("<br>" + "<br>"); out.println("<input type=submit>"); out.println("</form>"); out.println("</body>"); out.println("</html>"); } }
サーブレットを初めて起動すると、次の画面が表示されます。
「Jimmy」および「Geek」と入力して「Submit Query」をクリックすると、次の画面が表示されます。
開発のヒント
このサーブレットはHTTP |
前の例は、HTTP GET
メソッドを使用するため、リクエスト・パラメータ名および値がサーブレットURLに追加されます。これを避ける(通常、セキュリティを考慮して)ために、かわりにPOST
メソッドを使用することができます。次のコードでは、フォームでPOST
メソッドを使用し、doPost()
メソッドを使用してdoGet()
メソッドをコールするように、前の例が変更されています。変更箇所は、太字で強調されています。
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestParamExample extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Parameter Example" + "</h3>"); String firstName = request.getParameter("firstname"); String lastName = request.getParameter("lastname"); out.println("First and last name from request:" + "<br>" + "<br>"); if (firstName != null || lastName != null) { out.println("First name "); out.println(" = " + firstName + "<br>"); out.println("Last name "); out.println(" = " + lastName + "<br>"); } else { out.println("(No names entered. Please enter first and last name.)"); } out.println("<P>"); out.print("<form action=\""); out.print("RequestParamExample\" "); out.println("method=POST>"); out.println("Enter a new first name: "); out.println("<input type=text size=20 name=firstname>"); out.println("<br>"); out.println("Enter a new last name: "); out.println("<input type=text size=20 name=lastname>"); out.println("<br>" + "<br>"); out.println("<input type=submit>"); out.println("</form>"); out.println("</body>"); out.println("</html>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } }
「HttpServletRequestインタフェースの主要メソッド」には、HTTPリクエストに関する情報を取得するために使用できるリクエスト・オブジェクトのメソッドがいくつか示されています。この項では、リクエスト・オブジェクトの情報メソッドをコールして情報を出力するサンプル・コードを示します。
PrintWriter out = response.getWriter(); ... out.println("Method:"); out.println(request.getMethod()); out.println("Request URI:"); out.println(request.getRequestURI()); out.println("Protocol:"); out.println(request.getProtocol());
この例は、HTTPメソッド(GET
、POST
など)、リクエストURI(この例では、コンテキスト・パスとサーブレット・パスで構成されます)、プロトコル(HTTPなど)を取得して表示します。次の項には、例の全体が示されています。
この項では、HTTPメソッド、リクエストURIおよびプロトコルを取得してHTML表に出力するサーブレットの全体を示します。
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestInfoExample extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Info Example" + "</h3>"); out.println("<table border=0><tr><td>"); out.println("Method:"); out.println("</td><td>"); out.println(request.getMethod()); out.println("</td></tr><tr><td>"); out.println("Request URI:"); out.println("</td><td>"); out.println(request.getRequestURI()); out.println("</td></tr><tr><td>"); out.println("Protocol:"); out.println("</td><td>"); out.println(request.getProtocol()); out.println("</td></tr>"); out.println("</table>"); out.println("</body>"); out.println("</html>"); } }
このコードを実行すると、次のような画面が表示されます。
多くのサーブレットは、別のサーブレットのレスポンスをインクルードしたり、別のサーブレットにリクエストを転送するなど、別のサーブレットを処理時に使用します。次の項では、これらの機能について説明し、例を示します。
サーブレットの用語では、サーブレットのインクルードは、サーブレットが別のサーブレットからのレスポンスを自らのレスポンスに含める処理を指します。処理およびレスポンスは、最初は元のクライアントによって処理され、次にインクルードされたサーブレットに渡され、インクルードされたサーブレットが完了した後に元のサーブレットに返されます。
サーブレットの転送では、処理は転送コールまでは元のサーブレットによって行われます。転送コールの時点で、レスポンスがリセットされ、ターゲット・サーブレットがリクエストの処理を引き継ぎます。レスポンスがリセットされると、出力ストリーム内のHTTPヘッダー設定および情報は、すべてレスポンスから消去されます。転送後、元のサーブレットは、ヘッダーの設定やレスポンスへの書込みはできません。また、レスポンスがすでにコミットされている場合、サーブレットは転送または別のサーブレットのインクルードを行うことはできません。
別のサーブレットを転送またはインクルードするには、そのサーブレットのリクエスト・ディスパッチャを取得する必要があります。リクエスト・ディスパッチャは、HTTPリクエストを代替サーブレットにディスパッチするメカニズムです。次のいずれかのサーブレット・コンテキスト・メソッドを使用します。
RequestDispatcher getRequestDispatcher(String path)
RequestDispatcher getNamedDispatcher(String name)
getRequestDispatcher()
の場合、ターゲット・サーブレットのURIパスを入力します。getNamedDispatcher()
の場合、web.xml
ファイル内のそのサーブレットの<servlet-name>
要素に基づいて、ターゲット・サーブレットの名前を入力します。
いずれの場合も、返されるオブジェクトは、javax.servlet.RequestDispatcher
インタフェースを実装するクラスのインスタンスです。(このクラスはサーブレット・コンテナによって提供されます。)リクエスト・ディスパッチャは、ターゲット・サーブレットのラッパーです。一般に、リクエスト・ディスパッチャの役割は、ラップ対象のリソースにリクエストをルーティングする際の媒介として機能することです。
リクエスト・ディスパッチャには次のメソッドがあり、インクルードまたは転送を実行します。
void include(ServletRequest request, ServletResponse response)
void forward(ServletRequest request, ServletResponse response)
このように、これらのメソッドをコールする際には、サーブレット・リクエストおよびレスポンス・オブジェクトを渡します。
サーブレット・インクルードは、次のことを実行する際に役立つ方法です。
元のサーブレットの出力に加えて、ターゲット・サーブレットの出力もインクルードします。
これらのことは、サーブレット転送にも同様に当てはまりますが、転送の場合は、元のサーブレットの出力に「加えて」ではなく、ターゲット・サーブレットの出力が元のサーブレットの出力の「かわり」であることに注意してください。
この項では、インクルードまたは転送を実装する基本手順を示します。
javax.servlet.Servlet
インタフェースで示される)のgetServletConfig()
メソッドを使用して、サーブレット構成オブジェクトを取得します。
ServletConfig config = getServletConfig();
getServletContext()
メソッドを使用して、サーブレットのサーブレット・コンテキスト・オブジェクトを取得します。
ServletContext context = config.getServletContext();
getRequestDispatcher()
またはgetNamedDispatcher()
メソッドを使用して、RequestDispatcher
オブジェクトを取得します。getRequestDispatcher()
の場合は、ターゲット・サーブレットのURIパスを指定し、getNamedDispatcher()
の場合は、web.xml
ファイル内の関連する<servlet-name>
要素に基づいて、ターゲット・サーブレットの名前を指定します。
RequestDispatcher rd = context.getRequestDispatcher("path"); RequestDispatcher rd = context.getNamedDispatcher("name");
forward()
またはinclude()
メソッドを使用して、インクルードまたは転送をそれぞれ実行します。サーブレット・リクエストおよびレスポンス・オブジェクトを渡します。
rd.include(request, response); rd.forward(request, response);
次の例のように、4つの手順すべてを単一の文に組み合せることができます。
getServletConfig().getServletContext().getRequestDispatcher ("path").include(request, response);
次の項には、サーブレット・インクルードの例の全体が示されています。
この項では、別のサーブレットの出力をインクルードするサーブレットの例の全体を示します。 「リクエスト情報を取得する例の全体」に示されているRequestInfoExample
クラスが、「単純なサーブレットの例」に示されているHelloWorld
クラスを多少変更したものからの出力をインクルードするように更新されています。
次に、Hello Worldの例を多少変更したものを示します。このクラスの出力がインクルードされます。このクラスは、HelloIncluded
と呼ばれます。パッケージには含まれません。
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloIncluded extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Hello World!</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hi Amy!</h1>"); out.println("</body>"); out.println("</html>"); } }
次に、更新されたリクエスト情報クラスの例を示します。このクラスは、RequestInfoWithInclude
と呼ばれ、HelloIncluded
からの出力をインクルードします。主要なコードは、太字で強調されています。
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class RequestInfoWithInclude extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("<h3>" + "My Request Info Example" + "</h3>"); out.println("<table border=0><tr><td>"); out.println("Method:"); out.println("</td><td>"); out.println(request.getMethod()); out.println("</td></tr><tr><td>"); out.println("Request URI:"); out.println("</td><td>"); out.println(request.getRequestURI()); out.println("</td></tr><tr><td>"); out.println("Protocol:"); out.println("</td><td>"); out.println(request.getProtocol()); out.println("</td></tr>"); out.println("</table>"); out.println("</body>"); out.println("</html>"); getServletConfig().getServletContext().getRequestDispatcher ("/mypath/helloincluded").include(request, response); } }
パスの/mypath/helloincluded
は、コンテキスト・パスおよびサーブレット・パスで構成されるURIです。アプリケーションは、次のように、HelloIncluded
を直接リクエストすることもできるように構成されているものとします。
http://host:port/mypath/helloincluded
関連情報については、第2章「サーブレットのデプロイおよび起動」を参照してください。
同様に、次の例のように、サーブレットのかわりにJSPページをインクルードすることもできます。
getServletConfig().getServletContext().getRequestDispatcher ("/mypath/hello.jsp").include(request, response);
RequestInfoWithInclude
を実行すると、次のような画面が表示されます。
リクエスト・オブジェクトとレスポンス・オブジェクトは、通常、サーブレット・コンテナとサーブレット間で直接受け渡されます。ただし、サーブレット仕様では、サーブレット・フィルタを使用できます。このフィルタは、サーバーで実行され、リクエストをラップして前処理するため、またはレスポンスをラップして後処理するために、サーブレットとサーブレット・コンテナの中間に置くことができるJavaプログラムです。フィルタは、サーブレット構成でフィルタがマップされているリソースについてのリクエストが存在する場合に起動されます。
フィルタは、リクエストやレスポンスを効率的に変換することができます。サーブレットのグループの前処理または後処理を適用する場合は、フィルタを使用してください。(1つのサーブレットについてのみリクエストまたはレスポンスを変更する場合は、フィルタの作成は不要です。サーブレット自体に直接必要な変更を加えることができます。)
リソースにアクセスしたりそのリソースへのリクエストを起動前に前処理したりする場面や、カスタマイズされたリクエスト・オブジェクトまたはレスポンス・オブジェクトでリクエストやレスポンスをそれぞれラップする場面などでフィルタを使用できます。指定された順番で一連のフィルタを使用してサーブレットに対して操作することができます。
暗号化フィルタがその一例です。アプリケーション内のサーブレットは、機密に関わるレスポンス・データを生成することがあります。このようなデータは、特にHTTPなどのセキュアでないプロトコルを使用して接続が確立さている場合は、クリアテキスト形式でネットワーク上に発信しないようにする必要があります。フィルタによって、レスポンスを暗号化できます。(この場合は当然、クライアント側でレスポンスを復号化できる必要があります。)その他の例は、認証、ロギング、監査、データ圧縮およびキャッシュのためのフィルタです。
詳細は、第4章「サーブレット・フィルタの理解および使用方法」を参照してください。
サーブレット仕様には、イベント・リスナーを使用してWebアプリケーションの主要イベントを追跡する機能が追加されました。リスナーを実装して、アプリケーション・イベント、セッション・イベントまたはリクエスト・イベントをアプリケーションに通知することができます。この機能を使用すると、イベントの状態に基づいたリソース管理と自動処理をより効果的に実行できます。
次のいずれかをアプリケーションに通知する理由がある場合は、イベント・リスナーを使用してください。
例として、データベースにアクセスするサーブレットで構成されたWebアプリケーションについて考えます。サーブレット・コンテキストのライフ・サイクル・イベント・リスナーを作成して、データベース接続を管理することができます。このイベント・リスナーは次のように機能します。
イベント・リスナー・クラスは、web.xml
デプロイメント・ディスクリプタで宣言され、アプリケーションの起動時に起動され、登録されます。イベントが発生すると、サーブレット・コンテナは適切なイベント・リスナー・メソッドをコールします。
詳細は、第5章「イベント・リスナーの理解および使用方法」を参照してください。
例外が発生しても処理するためのエラー・ページが存在しない場合に表示されるエラー・メッセージで、次の点が変更されました。
次のエラー・メッセージが、セキュリティ依存例外の場合に表示されます。
サーブレット・エラー: 例外が発生しました。セキュリティ上の理由により、このレスポンスには含まれません。詳細はアプリケーション・ログを確認してください。
その他の例外の場合は、次のエラー・メッセージが表示されます。
サーブレット・エラー: 例外が発生しました。現在のアプリケーション・デプロイメント・ディスクリプタでは例外をこのレスポンスに含めることはできません。詳細はアプリケーション・ログを確認してください。
実行するテストが、例外またはスタック・トレースの表示に依存する場合は、アプリケーションを開発者モードで実行すると、スタック・トレースを表示できます。
アプリケーションを開発モードで実行するには、orion-web.xml
ファイルで<orion-web-app>
要素のdevelopment
属性を"true"
に設定します。
次に例を示します。
<?xml version="1.0"?> <orion-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/orion-web-10_0.x sd" deployment-version="null" deployment-time="1152223108413" jsp-cache-directory="./persistence" jsp-cache-tlds="standard" temporary-directory="./temp" context-root="/DevelopmentThrowException" schema-major-version="10" schema-minor-version="0" development="true"> <!-- Uncomment this element to control web application class loader behavior. <web-app-class-loader search-local-classes-first="true" include-war-manifest-class-path="true" /> --> <web-app> </web-app> </orion-web-app>}}
この項では、サーブレットまたはJSPモジュール、あるいはその両方をインクルードするWebアプリケーションのApache TomcatからOC4Jへの移行に関する情報について説明します。 次の項目について説明します。
この項では、JavaサーブレットのTomcatからOracle Application Serverへの移行に関する指針を示します。 この項には、次の項目が含まれます。
JavaサーブレットはTomcatからOC4Jへ簡単に移行でき、Tomcat環境で選択した内容に応じて、移行したサーブレットへのコードの変更はほとんど必要ないか、まったく必要ありません。
Oracle Application Server 10gリリース3(10.1.3.x)は、Sun社のJ2EEサーブレット仕様、バージョン2.4に完全に準拠しています。 Tomcat 5.5も、バージョン2.4と互換性があります。
また、Oracle Application Server 10gリリース3(10.1.3.x)は、サーブレット2.3と下位互換があります。 つまり、標準2.3仕様に書き込まれたサーブレットは、OC4Jで正常に作動し、移行の手間は最小限で済みます。
サーブレットを新しい環境に移行する場合の主なタスクは、構成とデプロイです。
サーブレットの移行に関係するタスクは、サーブレットのパッケージとデプロイの方法によって異なります。 サーブレットは、単純なサーブレットとして、標準ディレクトリ構造内でその他のリソースとともにパッケージされるWebアプリケーションとして、またはWebアーカイブ(WAR)ファイルとしてデプロイできます。
次に、サーブレットをOC4Jに移行する一般的な手順を示します。
Oracle JDeveloperのツールとウィザードを使用すると、これらの手順を自動化できます。
単純なサーブレットは、簡単にOC4Jで構成およびデプロイできます。 手動でのサーブレットのデプロイ・プロセスは、TomcatとOC4Jで同一です。
サーブレットは、Webアプリケーションの一部として登録および構成する必要があります。 サーブレットを登録および構成する場合は、Webアプリケーション・デプロイメント・ディスクリプタにエントリをいくつか追加する必要があります。
次に、単純なサーブレットをデプロイする一般的な手順を示します。
web.xml
)を、サーブレット・クラスの名前およびサーブレットのリクエストを解決する際に使用するURLパターンで更新します。
WEB-INF/classes/
ディレクトリにコピーします。 サーブレット・クラス・ファイルにパッケージ文が含まれる場合、パッケージ文の各レベル別に、追加のサブディレクトリを作成します。 次に、サーブレット・クラス・ファイルは、そのパッケージのために作成した最下層のサブディレクトリに置く必要があります。
Webアプリケーションは、WARファイルとして構成およびデプロイできます。 OC4Jでこの処理を最も簡単に行うためには、Application Server Controlコンソール管理GUIを使用します。 または、WARファイルを適切なディレクトリに手動でコピーします。 これは、Tomcatでも同様です。
本番Webアプリケーションは、通常にWARまたはEARファイルを使用して、Oracle Application Serverコンソールまたはユーティリティを介してデプロイします。 Webアプリケーションの開発中、展開ディレクトリ形式を使用すると編集済コードのデプロイおよびテストが短時間でできます。
デプロイの詳細は、『Oracle Containers for J2EEデプロイメント・ガイド』を参照してください。
次に、WARファイルをTomcatからOC4Jに移行する一般的な手順を示します。
Webアプリケーションは、標準ディレクトリ構造または展開ディレクトリ形式に格納されたファイルの集合として構成およびデプロイもできます。 OC4Jでこの処理を行うためには、標準ディレクトリ構造のコンテンツをOC4Jインストール内の適切なディレクトリに手動でコピーします。 同じ方法を、Tomcatで使用できます。
主にWebアプリケーションの開発中に、Webアプリケーションを展開ディレクトリ形式でデプロイします。 これは、変更を短時間で簡単にデプロイおよびテストできる方法です。 本番Webアプリケーションをデプロイする場合は、WebアプリケーションをWARファイルにパッケージし、Application Server ControlコンソールでWARファイルをデプロイします。
次に、OC4Jで展開Webアプリケーションを手動でデプロイする一般的な手順を示します。
<ORACLE_HOME>/j2ee/home/applications
次に、アプリケーション・デプロイメント・ディスクリプタ<ORACLE_HOME>/config/application.xml
を次のように変更して、Webアプリケーションをインクルードします。
<web-module id="migratedHR" path="../applications/hrapp" />
<ORACLE_HOME>/config/default-web-site.xml
にエントリを追加して、WebアプリケーションをWebサイトにバインドします。
<web-app application="default" name="migratedHR " root="/hr" />
<ORACLE_HOME>/config/server.xml
ファイルに、新しい<application>
タグ・エントリを追加して、新しいアプリケーションを登録します。
server.xml
を変更して、それを保存する場合、OC4Jはこのファイルのタイムスタンプの変更を検出し、アプリケーションを自動的にデプロイします。 OC4Jを再起動する必要はありません。
TomcatからOC4Jに移植する際に、留意すべき問題を説明します。
Tomcatは、ServletContext
クラスの次のメソッドに関しては、サーブレット仕様に完全に準拠していません。
メソッドgetResource()
およびgetResourceAsStream()
は、パス・パラメータをとります。 このパスにより、WEB-INF/config.xml
のようなWebアプリケーション・ディレクトリ構造内のファイルにアクセスできます。
J2EE APIドキュメントおよび仕様では、次のように記述されています。
「パスは(/)で始まる必要があり、これは現在のコンテキスト・ルートと相対的であると解釈されます。」
Tomcatでは、サーブレット仕様とは異なり、パス名をスラッシュ(/)で始める必要がありません。
サーブレット仕様完全準拠のOC4Jは、最初にスラッシュ(/)が必要です。
ServletContext
クラスのファイルにアクセスする際には、パス名の最初に必ずスラッシュ(/)を付けるようにしてください。
OC4Jでは、複数の異なるJNDIコンテキスト・ファクトリの使用が可能で、それぞれのファクトリはInitialContext
を1つ作成し、異なる機能を持っています。
次のコンテキスト・ファクトリが、最も一般的に使用されます。
InitialContext
のデフォルト・コンストラクタをクラス・パスにjndi.properties
を含めずにコールする場合に、内部コンテキスト・ファクトリを取得します。
RMIInitialContextFactory
: OC4Jコンテナに接続する場合、このコンテキスト・ファクトリを一般的に使用します。 すべての構成が無視され、java:comp/env/
接頭辞は必要ありません。
ApplicationClientContextFactory
: このコンテキスト・ファクトリはJNDI環境(特に、META-INF/application-client.xml
において)を処理し、java:comp/env/
環境接頭辞を必要とします。
コードがXerces/Xalanに依存する場合、追加の手順が必要です。
この内容に関する詳細は、Metalinkを参照してください。
Tomcatでは、java:
comp
/
env
/
ResourceName
を使用して、web.xml
内の<resource-ref>
要素を定義せずに、リソースを参照できます。
OC4Jでは、web.xml
内の<resource-ref>
要素を必要とするか、またはルックアップは単にResourceName
のみです。
OC4Jでは、サーバーで定義されるデータソースに対して、デフォルトでこれを実行できます。
initialContext.lookup("jdbc/ScottDS")
一方、Tomcatでは次のようになります。
initialContext.lookup("java:comp/env/jdbc/ScottDS")
コードを変更せずにTomcatオプションを使用する必要がある場合、次のようにweb.xml
を変更して、リソースに<resource-ref>
エントリをインクルードします。
<resource-ref> <res-auth>Container</res-auth> <res-ref-name>jdbc/ScottDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> </resource-ref>
一般的に、OC4JのJ2EE仕様の解釈はTomcatよりも厳密です。
カスタムTomcat JSPタグを標準JSPタグに置き換えてから、OC4JでJSPページをデプロイすると、コンパイルの際の問題を回避できます。
仕様に「should」および「may」の語が使用される場合は、注意してください。 このような場合、選択が可能であり、その結果の動作が異なるため、このような場合は注意が必要です。
次に例を示します。 JSP仕様では、次のように述べられています。
この場合、OC4Jでは、JavaBeanがzero-args
コンストラクタを持たない場合、class
属性ではなくtype
属性を使用する必要があるという推奨事項を実装します。 Tomcatでは、type
属性は要求されませんが、class
属性を受け入れます。 この差異により、TomcatからOC4Jにアプリケーションを移行するときに次の問題が発生します。
index.jsp
でtype
属性を使用して、JavaBean(my.MyClass
)がpublicのno-args
コンストラクタを持たない場合、ページはTomcatおよびOC4Jの両方で正常に動作します。これが望ましい動作です。
望ましい使用方法の例を次に示します。
<jsp:useBean id="codeDesc" scope="session" type="my.MyClass"/>
一方、この状況でclass="my.MyClass"
属性を使用すると、Tomcatはこの使用を受け入れ、正常に動作します。 しかし、OC4Jは仕様をより厳密に解釈するので、OC4JではJSPCompilationException
がスローされます。
あまり厳密ではない使用方法の例を次に示します。
<jsp:useBean id="codeDesc" scope="session" class="my.MyClass"/>
この項では、OC4JとTomcatのクラスタリングの相互関係の概要を説明します。 次の項目について説明します。
OC4Jでは、クラスタリングは、デプロイされている場合、アプリケーションごとの基準で定義されます。
構成の方法など、OC4Jのクラスタリングの詳細は、『Oracle Containers for J2EE構成および管理ガイド』の第9章「OC4Jでのアプリケーションのクラスタリング」を参照してください。
ロード・バランシングの詳細は、『Oracle HTTP Server管理者ガイド』の付録Dを参照してください。
Tomcatでは、server.xmlファイル内の<cluster>要素およびそのサブ要素を使用してクラスタリングを構成します。 クラスタリングは、コンテナごとに有効になります。
OC4Jでは、デプロイされたアプリケーションのorion-application.xmlファイル内の<cluster>要素を使用して、アプリケーションごとにクラスタリングを定義します。
これにより、有効化されたクラスタリングを使用および使用せずに、アプリケーションが同一のOC4Jインスタンス内に共存できるようになります。 対象のアプリケーションのorion-application.xmlファイルを使用して、OC4J内のクラスタリングを構成します。 デフォルト・アプリケーションのクラスタリングを有効にすると、すべてのデプロイ済のアプリケーションがその設定を継承するので、コンテナ・レベル・クラスタリングが有効になります。 また、OC4Jでは、アプリケーションごとにクラスタリングを構成するため、異なるプロトコルおよび異なるオプションを使用し、異なるアプリケーションを構成してクラスタリングを有効化できます。
Tomcatでは、IPマルチキャストおよびIPソケットの両方を使用して、容易にクラスタリングできます。 用語の面では、Tomcatには単一メモリー内のレプリケーション・オプションがあり、これにより2つのネットワーク・モデルを結合します。
OC4Jの場合は、メモリー内セッション状態レプリケーションの使用方法および用語が異なります。 OC4Jでセッション状態のメモリー内をレプリケートする方法は2つあり、IPマルチキャストまたはIPソケットのいずれも使用できます。 どちらの場合も、グループ・メンバーシップ・アクティビティは同一のネットワークを使用します。
OC4Jを構成して、IPマルチキャストをレプリケーション・プロセスとして使用する場合、OC4JはIPマルチキャストをグループ・メンバーシップ・プロトコルに参加する手段として使用し、セッション状態をグループの他のメンバーに配布します。 マルチキャスト・ネットワーク・アドレスは、既知の値をデフォルトにします。 これは、<cluster>要素の<multicast>サブ要素を使用して、任意に構成できます。 OC4Jではマルチキャスト・レプリケーション・プロトコルには保証付き配信の追加された値があるため、実際に使用されているネットワーク・モデルに信頼性保証が備わっていない場合でも、OC4Jでの使用方法により、すべてのパケットが配信され、セッション状態が失われないことが保証されます。
OC4Jを構成して、ピアツーピアをレプリケーション・プロトコルとして使用する場合、OC4JはIPソケットをグループ・メンバーシップ・プロトコルに参加する手段として使用し、セッション状態を選択したピアに配布します。 OC4Jを独立して使用する場合(スタンドアロン)、ピアのリストは構成ファイル内で静的に定義する必要があります。 TCOソケット・アドレスのデフォルトは、既知の値です。 これは、クラスタ・プロトコル、タグのサブ要素を使用して構成できます。
OC4JをOracle Application Server環境で使用する場合(クラスタ化)、ピアの初期リストがOPMNサーバーから提供されます。 また、OPMNはピア・レプリケーション・プロトコルで使用されるポート番号を割り当てるため、複数のOC4Jインスタンスを起動したサーバー上でポートの競合が発生しません。
Tomcatは次のメカニズムをサポートして、セッション状態のその他のTomcatインスタンスへの配布を処理します。
OC4Jは、次のセッション永続性メカニズムをサポートします。
OC4Jがサポートするメモリー内ベースのレプリケーションに2つの方法(マルチキャストおよびピア)があることと、Tomcatは両方を組み合せて使用して、メモリー内レプリケーションをサポートすることを、混同しないようにしてください。
OC4Jは、ファイルベース状態レプリケーション・プロトコルはサポートしません。
OC4Jでは、「状態永続性」ではなく「レプリケーション・プロトコル」の用語を使用します。
<protocol>
タグを使用し、<multicast>
、<peer>
または<database>
サブタグのいずれか1つを指定してどのプロトコルを使用するかを示し、orion-application.xml
ファイル内の値として構成されます。 データベース・レプリケーション・プロトコルには、データソースのJNDIロケーションが必要で、これが状態のレプリカが格納されるデータベース・インスタンスを示します。
Tomcatでは、レプリケーションされた状態のタイプは、完全なセッションまたは変更セットだけで構成されます。 レプリケーション・タスクの実行に使用されるクラスを指定して、構成します。
OC4Jは、完全なセッションまたはデルタのみのいずれかを送信する同様の概念をサポートします。 <replication-policy>
要素およびscope
属性を使用して、構成することができます。 オプションは、modifiedAttributes
またはallAttributes
です。
Tomcatでは、状態レプリケーションの送信は、同期、非同期またはプールされるよう構成されます。
OC4Jはデフォルトでは、非同期レプリケーション・モデルをレプリケーション送信に使用します。 これは同期レプリケーション・オプションを使用して同期に変更可能で、レプリカを送信するOC4Jインスタンスは、受信OC4Jからの確認を待ってから続行します。
クラスタ化環境で実行するアプリケーションに対する、OC4JおよびTomcatのアプリケーション設計要件は共通です。
Tomcatは組込みHTTPサーバーを提供します。 ただし、汎用Apache HTTPサーバーをmod_proxy
またはmod_rewrite
、またはAJPベースのmod_jk
コネクタで使用して拡大し、複数のTomcatインスタンス間をルーティングすることができます。
OC4Jもまた組込みHTTPサーバーを提供します。 ただし、提供される自動ロード・バランシング機能を拡大し、その恩恵を受けるには、Oracle HTTPサーバーを使用することをお薦めします。 OC4J HTTPを使用するには、サード・パーティのロード・バランシング・コンポーネントが必要です。
Oracle Application Server環境では、OC4Jインスタンスで実行中のアプリケーションにリクエストをルーティングするために、Oracle HTTP Serverが使用されます。 Oracle HTTP Serverは、同一のクラスタ・トポロジで実行中のOC4Jインスタンスを検出するよう構成されます。 アプリケーションはOC4Jインスタンスにデプロイされるため、Oracle HTTP Serverは新しいデプロイの更新を自動的に受信し、アプリケーション・コンテキスト・ルートをルーティング可能なURLのリストに自動的に追加します。
Oracle HTTP Serverは、セッション・ベースのリクエストはフェイルオーバーが発生するまで常に同一のOC4Jインスタンスにルーティングされるよう、スティッキー・セッションをサポートするクラスタ化されたアプリケーションの自動フェイルオーバーを提供します。
Oracle HTTP Serverは、デフォルトでラウンドロビン・ロード・バランシング・アルゴリズムを使用します。 ロード・バランシング・モデルは、いくつかの異なるオプションに変更できます。
詳細は、『Oracle HTTP Server管理者ガイド』の付録D「mod_oc4jを使用するロード・バランシング」を参照してください。
|
![]() Copyright © 2006 Oracle Corporation. All Rights Reserved. |
|