<?xml version="1.0" encoding="Shift_JIS"?>
<document>

  <properties>
    <author email="jon@latchkey.com">Jon S. Stevens</author>
    <title>You make the decision - Error Handling</title>
    <translator>熊坂祐二</translator>
    <original>ymtd/ymtd-error-handling</original>
  </properties>

<body>

<section name="エラーの扱い">

<p>
これは、JSP による出来すぎた基本設計の問題です。
質問：
JSP を使うとき、いったい何種類のエラーに遭遇するでしょうか?
例えば、JSP Servlet が、.jsp テキスト・ファイルから自動生成されて、
コンパイラでコンパイルされ、生成/解析エラーやコンパイルエラーが
あるときにどうなるでしょうか？
JSP の不必要な複雑さは、実際のところエラーを誘発する方法をたくさん増やしているのです！
</p>

<p>
この全ての最も醜い面は、エラーが 2 つの異なる仕組みを通して報告されるということです。
パーサーは、生成レイヤの結果として、独自のエラーのセットと javac コンパイラが投げる異なったエラーのセットを投げることができ、コンパイラからのエラーは、一切区別することが
できないのです。例えば、あなたはこのエラーが何を伝えようとしているのか、私に説明できますか？
</p>

<source><![CDATA[
org.apache.jasper.JasperException: Unable to compile class: Invalid type
expression.
                out.println("JSP is great!")
                           ^
: Invalid declaration.
                out.write("\r\n\r\n\r\n");
                         ^
2 errors
]]></source>

<p>
あなたは、その原因を推測できたでしょうか? 
エラーは最初の out.println() の後に<code>;</code>が不足していたためでした。
さて、あなた自身にこれまで誰も書いたことや見たことのない、
Javaコードの行に取り掛かる状態です。
あなたは、人が素早く、そして、簡単にエラーを理解することができたと思いますか？
抽象のレベルが本来の.jspファイルからあるので、
それをエラーがファイルのより限定的でない部分の上にあったならば、
エラーの発生場所を見つけることは今や非常により難しいということを認識してください。
そして、中間 .java ファイルがあるので、それは発生します。
</p>

<p>
さらに、Velocityは中間ステップも、抽象化のレイヤもないのでいので、
これらの同じ問題で苦しむことはありません、
</p>

<source><![CDATA[
<%@ page errorPage="/error.jsp" %>
]]></source>

<p>
JSP も Throwable な例外がページの処理中に投げられたときに
使用するエラー・ページを定義することができます。
これは再び MVC モデルを破壊することになりませんか？
言い換えれば、アプリケーションフレームワークが
エラー・メッセージを扱うことに対して責任がないのです。
</p>

<source><![CDATA[
<% throw new Exception("oops"); %>
]]></source>

<p>
JSP ページのどこかで Exception を投げるために、
ステートメントの中に最初にそれを埋め込む必要があります。
注意: この特定の場合、最適化がコンパイラで有効にされるならば、
この特定の場合にはチャンスがそれであるために、全ての例外は外へコンパイルされます。
したがって、より具体的なオブジェクトが、「本当の」ものの代わりに使われなければなりません。
厳しいMVCモデルを使うならば、オブジェクトのinstantiationがビューを壊すので、これは実際に難しいと判明することができます。

</p>

<source><![CDATA[
<%
  if (true) {
    throw new Exception("oops");
  }
%>]]></source>

<p>
理由は、JSP が例外の後に追加の<code>out.println("\r\n");</code>を生成する
ことになるということです。
javac がページをコンパイルしようとするときに、
別のデバッグをするのに難しい報告になります。
</p>

<source><![CDATA[
org.apache.jasper.JasperException: Unable to compile class for
  JSPC:\engines\jakarta-tomcat\work\localhost_8080%2Fjsp\
  _0002ferrorMaker_0002ejsperrorMaker_jsp_3.java:75:
Statement not reached.
                out.write("\r\n");
                ^]]></source>

<p>
直接 Jason の書籍(私が説明するより良いので)から引用すると
</p>

<source><![CDATA[
実際には、多くの「よしっ。分かった!」がJPSスクリプトを
使用しているときに発生します。偶然に式を書き忘れて(=記号
を忘れて)スクリプトレットを書いてしまったり、(staticは許されない)
スクリプトレット内部でstatic変数の定義をしたり、セミコロンを
忘れたり(式には不要だが、スクリプトレットには必要)、または
偶然完全な Java コードを書いてしまったりして、コンパイラが
生成した Java コードを実行しようとして混乱したエラーメッセージ
を JSP ファイル以外から受け取ることになる。この問題を示すために、
errorTaker.jsp ファイルで <%= name %> とするところを
<% name %> としてみよう。
Tomcat は、次のエラーを出力してくる。

org.apache.jasper.JasperException: Unable to compile class for
  JSPC:\engines\jakarta-tomcat\work\localhost_8080%2Fjsp\
  _0002ferrorTaker_0002ejsperrorTaker_jsp_6.java:91:
Class name not found.
                 name 
                 ^

多くの場合このようなエラーを除去することは、プログラマーに
エラーを引き起こしたことを再現するために発生するコードを
見なければなりません。]]></source>

<p>
Velocity では、テンプレート内部にどんな Java コードも埋め込むことを
許可していないため、同じ問題は発生しようがありません。
テンプレートで唯一許されるのは Velocity テンプレート言語（VTL）と
メソッド呼び出しだけです。
</p>

<p>
他のすべてはパーサーによって無視されます。
人が Velocity の範囲内でトラブルに出くわす唯一の場合は実行時の間、
例外を投げるメソッドの呼び出しです。
例えば、この VTL はそれの上でその<code>substring()</code>メソッドを呼ぶ<code>$foo</code>と
それから試みが<code>IndexOutOfBoundsException</code>に投げるストリングを定義します：
</p>

<source><![CDATA[
#set ($foo = "bar")

#set ($bar = $foo.substring(0,10))
]]></source>

<p>
例外が投げられるとき、パーサーは処理を停止し、例外は
スタックツリーを遡り、パーサーを実行する原因となったメソッドにおいて、
例外を捕捉します。その時、例外は美しく取り扱うことができます。
そう、これは Java 知識のないデザイナーにとってデバッグは容易ではなく、
少なくとも限定された Java 知識のあるテンプレートエンジニアは簡単に
デバッグできます。
</p>

<p>
これは Velocity と組み合わせられる Turbine を使う利点のうちの1つです。
というのは Turbine の設計は、一貫性のある方法で例外を取り扱うからです。
また、VelocityServlet に含む形で Velocity を使うことによって、
これと同じ機能を得ることは可能です。
例外は、エラーが発生した.vmファイルにおいて、行番号とカラム番号を含むことになります。
JSP のような抽象性がないので、エラーの行番号とカラム番号が一致します。
また、例外を投げることになる唯一のツールは、パーサーです。
発生する.java コードの結果である隠れた javac メッセージをデバッグする必要はありません。注:商用のアプリケーションサーバの中には、エラー時に JSP ファイルの行番号を
うまく扱うものがあります。
</p>

<p>
あなたが判断してください。
</p>
<p>
<strong>[ <a href="ymtd-generation.html">生成?</a> &lt;- 前 | 
    次 -&gt; <a href="./ymtd-javabeans.html">JavaBeans</a> ]
</strong></p>

</section>

</body>
</document>
