## Flowletの開発

- お約束のHello World
- リテラル値
- 引数
- 引数のデフォルト値
- 戻り値
- 変数
- 値の代入
- プロパティ
- caseタグによる条件分岐
- forタグによるループ
- 定数
- Javaの定数のインクルード
- Javaのメソッド呼び出し
- Ruletの呼び出し
- Flowletの呼び出し
- 配列
- throw処理
- 事前条件
- 自動トランザクション制御
- 関数と演算子

## お約束のHello World

それでは、さっそく使ってみましょう。XMLを次のように記述します。

    <flowlet>
        <stmt>out.println('Hello World')</stmt>
    </flowlet>

flowletタグの中に、ロジックのタグを記述していきます。
stmtタグで、1つの文を実行します。outは、JavaのSystem.outをあらわす ビルトインのオブジェクトです。
printlnのようにJavaのメソッドをそのまま呼び出すことができます。
Flowletでは文字列は、Javaとは違って、シングルコーテーションで囲みます。

このファイルをHelloFlowlet.xmlという名前で、examples.org.seasar.nazunaパッケージに 置きます。
実際は、WEB-INF/classes/examples/org/seasar/nazuna/HelloFlowlet.xmlに置くことになります。
Eclipseの場合は、WEB-INF/src以下に置いておくと、自動的にWEB-INF/classesにコピーしてくれます。

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;
    import org.seasar.util.SeasarException;

    public class HelloFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.HelloFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (SeasarException ex) {
                ex.printStackTrace();
            }
        }
    }

Nazuna.execute()の第1引数にFlowletの名前を指定して実行します。
名前は、パッケージ名 + . + ファイル名から拡張子を除いたものになります。
Hello Worldと表示されたらOKです。

## リテラル値

文字列(java.lang.String)は、'abc'のようにシングルクォーテーションで囲みます。
数値(java.lang.Integer)は、123のように数値を記述します。
12345678901のようなintの範囲を超える数値は、java.lang.Longにマッピングされます。
1.2のような小数点を含む数値は、java.lang.Doubleにマッピングされます。
Flowletでは、リテラル値もすべてオブジェクトとして扱われます。

## 引数

Flowletに対して、引数を渡したいときは、Ruletと同様に
Nazuna.execute()の第2引数以降に指定します。
引数の順番は、argタグの順番にあわせます。

    Nazuna.execute(FLOWLET_NAME, 'Nazuna');

引数は、inputタグの子要素のargタグを使い、引数名をname属性に指定します。
また、className属性にJavaの型を指定します。
文字列の連結は、||を使います。
引数名は、英小字で始め、ドット(.)を含んではいけません。

#### examples.org.seasar.nazuna.ArgFlowlet

    <flowlet>
        <input>
            <arg name="name" className="java.lang.String"/>
        </input>
        <stmt>out.println('Hello ' || name)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックを記述します。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ArgFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ArgFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME, "Nazuna");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行すると、Hello Nazunaと表示されるはずです。

## 引数のデフォルト値

ルールによっては、引数が指定されなかった場合に、デフォルトの値が
適用されて欲しい場合があります。
argタグのボディで、デフォルト値を指定することもできます。

#### examples.org.seasar.nazuna.ArgDefaultValueFlowlet

    <flowlet>
        <input>
            <arg name="name" className="java.lang.String">'World'</arg>
        </input>
        <stmt>out.println('Hello ' || name)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックを記述します。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;
    import org.seasar.util.SeasarException;

    public class ArgDefaultValueFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ArgDefaultValueFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (SeasarException ex) {
                ex.printStackTrace();
            }
        }
    }

実行すると、Hello Worldと表示されるはずです。

## 戻り値

Flowletから値を返すときは、returnタグを使います。
また、戻り値のオブジェクトの型は、outputタグのclassName属性で指定します。

    <flowlet>
        <output className="java.lang.String"/>
        <return>'Hello'</return>
    </flowlet>

Java側では、Nazuna.execute()の戻り値になります。
このファイル(examples.org.seasar.nazuna.ReturnFlowlet)を呼び出す Javaのロジックを記述します。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ReturnFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ReturnFlowlet";

        public static void main(String[] args) {
            try {
                String ret = (String) Nazuna.execute(FLOWLET_NAME);
                System.out.println(ret);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行すると、Helloと表示されるはずです。

## 変数

変数は、localタグの子要素のvarタグで指定します。
name属性が変数名になります。className属性で変数の方を指定します。
varタグのボディで、デフォルト値を指定することもできます。
変数名は、英小字で始め、ドット(.)を含んではいけません。

    <local>
        <var name="a" className="java.lang.String"/>
        <var name="b" className="java.lang.String">'aaa'</var>
        <var name="c" className="java.lang.Integer">123</var>
        <var name="d" className="java.lang.Double">1.0</var>
        <var name="e" className="java.util.Date">new java.util.Date()</var>
    </local>

aは、java.lang.Stringの変数で、初期値はnullになります。
bは、java.lang.Stringの変数で、初期値は'aaa'になります。
cは、java.lang.Integerの変数で、初期値は123になります。
dは、java.lang.Doubleの変数です。 小数点を含む場合、java.lang.Doubleにマッピングされます。
eのように、コンストラクタを使って、任意のオブジェクトを作成できます。

#### examples.org.seasar.nazuna.VariableFlowlet

    <flowlet>
        <local>
            <var name="a" className="java.lang.String"/>
            <var name="b" className="java.lang.String">'aaa'</var>
            <var name="c" className="java.lang.Integer">123</var>
            <var name="d" className="java.lang.Double">1.0</var>
            <var name="e" className="java.util.Date">new java.util.Date()</var>
        </local>
        <stmt>out.println(a)</stmt>
        <stmt>out.println(b)</stmt>
        <stmt>out.println(c)</stmt>
        <stmt>out.println(d)</stmt>
        <stmt>out.println(e)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class VariableFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.VariableFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    null
    aaa
    123
    1.0
    Mon May 12 16:07:27 JST 2003

のようになります。

## 値の代入

値の代入は、変数 := 値のようにします。代入の演算子は、:=です。
引数のプロパティに代入することは可能です。

## プロパティ

JavaBeans、java.util.Mapのプロパティには、ドット(.)記法でアクセスできます。
JavaBeansのプロパティ名は、getXxx()のようなメソッドがあったとするとXxxの先頭を小文字にした
xxxになります。Mapのキーもそれにあわせて小文字で始めるようにしてください。
プロパティ名を大文字で始めると、Nazunaにクラス名と勘違いされる可能性があります。
例えば、次のようなJavaBeansを作成したとします。

    package examples.org.seasar.nazuna;

    import java.io.Serializable;

    public class MyBean implements Serializable {

        private int _myInt;
        private long _myLong;
        private String _myString;
        private double _myDouble;

        public double getMyDouble() {
            return _myDouble;
        }

        public int getMyInt() {
            return _myInt;
        }

        public long getMyLong() {
            return _myLong;
        }

        public String getMyString() {
            return _myString;
        }

        public void setMyDouble(double myDouble) {
            _myDouble = myDouble;
        }

        public void setMyInt(int myInt) {
            _myInt = myInt;
        }

        public void setMyLong(long myLong) {
            _myLong = myLong;
        }

        public void setMyString(String myString) {
            _myString = myString;
        }
    }

次のようにしてJavaBeansのプロパティにアクセスできます。

#### examples.org.seasar.nazuna.PropertyFlowlet

    <flowlet>
        <local>
            <var name="bean" className="examples.org.seasar.nazuna.MyBean"<
                new examples.org.seasar.nazuna.MyBean()
            </var>
        </local>
        <stmt>bean.myInt := 123</stmt>
        <stmt>out.println(bean.myInt)</stmt>
        <stmt>bean.myLong := 12345678900</stmt>
        <stmt>out.println(bean.myLong)</stmt>
        <stmt>bean.myDouble := 1.5</stmt>
        <stmt>out.println(bean.myDouble)</stmt>
        <stmt>bean.myString := 'aaa'</stmt>
        <stmt>out.println(bean.myString)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class PropertyFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.PropertyFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    123
    12345678900
    1.5
    aaa

になります。

## caseタグによる条件分岐

caseタグを使って、複数の条件に応じた処理を行うことができます。
caseタグによって、条件分岐がすっきり書け、条件の判定も豊富な 関数や演算子を
使えることが、Flowletの特徴といえるでしょう。

    <case>
        <when condition="booleanを返す式">
            ロジックタグ
            ロジックタグ
        </when>
        <when condition="booleanを返す式">
            ロジックタグ
            ロジックタグ
        </when>
        <else>
            ロジックタグ
            ロジックタグ
        </else>
    </case>

whenタグのcondition属性には、a = 1, a > 1 and a < 5などのboolean値を返す 論理式や 比較式を指定します。
condition属性がtrueと評価された場合は、ロジックタグ(stmtタグなど)が実行され、
以降のwhenタグやelseタグの処理はスキップされます。
falseと評価された場合は、次のwhenタグが処理されます。
すべてのwhenタグがfalseと評価された場合、elseタグが実行されます。

#### examples.org.seasar.nazuna.CaseFlowlet

    <flowlet>
        <input>
            <arg name="a" className="java.lang.Integer"/>
        </input>
        <case>
            <when condition="a = 1">
                <stmt>out.println('one')</stmt>
            </when>
            <when condition="a = 2">
                <stmt>out.println('two')</stmt>
            </when>
            <else>
                <stmt>out.println('other')</stmt>
            </else>
        </case>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class CaseFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.CaseFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME, new Integer(2));
            } catch (SeasarException ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    two

になります。

## forタグによるループ

forタグを使って、ループ処理を行うことができます。

    <for init="初期変数の処理" condition="ループを繰り返すかどうかの条件"
            next="次のループに入るときの処理">

        ロジックタグ
        ロジックタグ
    </for>

init属性でi := 1のような初期変数の処理をすることができます。
i := 1; j := 1のようにセミコロンで区切って複数の処理を記述することもできます。
変数は、varタグであらかじめ宣言しておく必要があります。
condition属性では、i le 5のようなループを繰り返す条件を指定します。
<,>を含んだ比較は、比較演算子を参照してください。
next属性でi := i + 1のような次のループに入るときの処理をすることができます。
複数処理の記述は、initタグと同様です。

#### examples.org.seasar.nazuna.ForFlowlet

    <fowlet>
        <local>
            <var name="a" className="java.lang.Integer">0</var>
            <var name="i" className="java.lang.Integer"/>
        </local>
        <for init="i := 1" condition="i le 5" next="i := i + 1">
            <stmt>a := a + i</stmt>
        </for>
        <stmt>out.println(a)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ForFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ForFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    15

になります。

#### for処理のbreak

breakタグを使って、forタグの処理を途中で中断することもできます。

#### examples.org.seasar.nazuna.ForBreakFlowlet

    <flowlet>
        <local>
            <var name="a" className="java.lang.Integer">0</var>
            <var name="i" className="java.lang.Integer"/>
        </local>
        <for init="i := 1" condition="i le 5" next="i := i + 1">
            <stmt>a := a + i</stmt>
            <case>
                <when condition="i = 3">
                    <break/>
                </when>
            </case>
        </for>
        <stmt>out.println(a)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ForBreakFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ForBreakFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    6

になります。

#### for処理のcontinue

continueタグを使って、continueタグ以降の処理をスキップし、次のループに入ることもできます。

#### examples.org.seasar.nazuna.ForContinueFlowlet

    <flowlet>
        <local>
            <var name="a" className="java.lang.Integer">0</var>
            <var name="i" className="java.lang.Integer"/>
        </local>
        <for init="i := 1" condition="i le 5" next="i := i + 1">
            <case>
                <when condition="i = 3">
                    <continue/>
                </when>
            </case>
            <stmt>a := a + i</stmt>
        </for>
        <stmt>out.println(a)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ForContinueFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ForContinueFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    12

になります。

#### while

Javaと同様のwhile処理を行いたい場合は、forタグのinit属性、 next属性を省略します。

## 定数

定数は、constタグを使って設定します。
name属性に設定した名前でアクセスします。
定数の名前は英大文字か数字にし、
複数の単語から構成される場合(例 CAR_NAME)は、単語と単語をアンダースコア(_)でつなぎます。
変数が、実行時に作成されるのに対し、
定数は、XMLのコンパイル時に作成されます。
定数に値を代入することはできません。

#### examples.org.seasar.nazuna.ConstFlowlet

    <flowlet>
        <const name="HELLO">'Hello World'</const>
        <stmt>out.println(HELLO)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ConstFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ConstFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    Hello World

になります。

## Javaの定数のインクルード

Javaでpublic static finalとして定義した定数をincludeタグを使って
自分の定数として取り込むことができます。
インクルードするJavaのクラス名は、className属性で指定します。

#### examples.org.seasar.nazuna.Constants

    package examples.org.seasar.nazuna;

    public interface Constants {

        int ONE = 1;
        String A = "a";

    }

#### examples.org.seasar.nazuna.IncludeFlowlet

    <flowlet>
        <include className="examples.org.seasar.nazuna.Constants"/>
        <stmt>out.println(ONE)</stmt>
        <stmt>out.println(A)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class IncludeFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.IncludeFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    1
    a

になります。

## Javaのメソッド呼び出し

#### インスタンスメソッド

Javaのインスタンスメソッドは、変数名.メソッド名(引数, ...)で、 次のようにして呼び出すことができます。

    <stmt>str := 'abc'</stmt>
    <stmt>str2 := str.toUpperCase()</stmt>
    <stmt>num := str.indexOf('b')</stmt>
    <stmt>str3 := str.substring(0, 1)</stmt>

ネストしたプロパティのメソッドも、変数名.プロパティ名.プロパティ名.メソッド名(引数, ...)で、
呼び出すことができます。

#### スタティックメソッド

Javaのスタティックメソッドは、パッケージ名を含んだクラス名.メソッド名(引数, ...)で、 呼び出すことができます。
クラス名は、Javaの慣習に従って大文字で始めてください。
小文字で始めると、Flowletは、プロパティと勘違いしてしまいます。

    <stmt>num := org.nazuna.util.MathUtil.pow(9.0, 3.0)</stmt>

Java側の型が、intの場合、Flowlet側はIntegerを使います。
Java側の型が、longの場合、Flowlet側はLongを使います。
Java側の型が、doubleの場合、Flowlet側はto_double()を使ってDoubleに変換します。
参照型の場合、Flowlet側のオブジェクトをそのまま使えます。

## Ruletの呼び出し

FlowletからRuletを呼び出すこともできます。仕様は次のようになります。
executeRulet(Ruletのクラス名, 引数, ...)
引数の意味はNazuna.executeRuletメソッドと同様です。
例えば、examples.org.seasar.nazuna.HelloRuletを呼び出すには次のようにします。

#### examples.org.seasar.nazuna.ExecuteRulet

    <flowlet>
        <const name="RULET_NAME">'examples.org.seasar.nazuna.HelloRulet'</const>
        <stmt>executeRulet(RULET_NAME)</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ExecuteRuletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ExecuteRulet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    Hello World

になります。

## Flowletの呼び出し

Flowletからexecute()を使って他のFlowletを呼び出すこともできます。
仕様は次のようになります。
execute(Flowlet名, 引数, ...)
引数の意味はNazuna.executeメソッドと同様です。
例えば、examples.org.seasar.nazuna.ArgFlowletを呼び出すには次のようにします。

#### examples.org.seasar.nazuna.ExecuteFlowlet

    <flowlet>
        <const name="FLOWLET_NAME">'examples.org.seasar.nazuna.ArgFlowlet'</const>
        <stmt>execute(FLOWLET_NAME, 'Nazuna')</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ExecuteFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ExecuteFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    Hello Nazuna

になります。

同様にして、executeQuery, executeUpdateも呼び出せます。

## 配列

配列もJavaと同様に扱えます。classNameは、java.lang.String[]のように
配列にしたいクラス名の後に[]を指定します。

#### examples.org.seasar.nazuna.ArrayFlowlet

    <flowlet>
        <local>
            <var name="array" className="java.lang.String[]"/>
            <var name="array2" className="java.lang.String[]"/>
        </local>
        <stmt>array := new java.lang.String[2]</stmt>
        <stmt>array[0] := 'aaa'</stmt>
        <stmt>array[1] := 'bbb'</stmt>
        <stmt>out.println(array[0])</stmt>
        <stmt>out.println(array[1])</stmt>
        <stmt>out.println('length:' || array.length)</stmt>
        <stmt>array2 := new java.lang.String[]{'ccc', 'ddd'}</stmt>
        <stmt>out.println(array2[0])</stmt>
        <stmt>out.println(array2[1])</stmt>
    </flowlet>

このFlowletを呼び出すJavaのロジックは次のようになります。

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class ArrayFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ArrayFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    aaa
    bbb
    length:2
    ccc
    ddd

になります。

## throw処理

例外を発生させるには、throwタグを使います。
今のところ、例外を捕捉する機能はありません。

#### examples.org.seasar.nazuna.Throw

    <flowlet>
        <throw>new java.lang.Exception('test')</throw>
    </flowlet>

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;
    import org.seasar.util.SeasarException;

    public class ThrowFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.ThrowFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME);
            } catch (SeasarException ex) {
                System.out.println(ex);
                System.out.println("cause:" + ex.getCause());
            }
        }
    }

実行結果は、

    ERROR 2003-12-31 16:41:02,513 [main]
    [ESSR0347]Exception ocurred at examples.org.seasar.nazuna.ThrowFlowlet:/flowlet[1]/throw[1],
      because java.lang.Exception: test
    org.seasar.util.SeasarException: [ESSR0017]Exception occurred, because java.lang.Exception: test
    cause:java.lang.Exception: test

になります。例外の起きた位置(/flowlet[1]/throw[1])も知ることができます。
これは、throwタグに限った話ではなく、Flowletで起きた例外は、
発生した位置を知ることができます。
SeasarException、RuntimeException、Errorをthrowするとそのままcatchできますが、
それ以外の場合、いったんSeasarExceptionでラップされます。
原因となった例外は、SeasarException.getCause()で取得できます。

SeasarExceptionをthrowする場合は、messageCode属性とargs属性を使うこともできます。

    <throw>new org.seasar.util.SeasarException('ESSR0028', 'a', 1)</throw>

の変わりに

    <throw messageCode="ESSR0028" args="'a', 1"/>

と省略して記述できます。

## 事前条件

Flowletを呼び出すときに、Flowletが期待している引数の条件を事前条件といいます。
例をあげると次のようなものがあります。

- nameが設定されていること
- priceは0以上であること

Flowletを呼び出す側は、事前条件を満たす責任があります。
Flowletは、事前条件が満たされていれば、正しい結果を返す義務(事後条件)があります。
このような考え方は｢契約によるプログラミング｣といわれ、
責任と義務をはっきりさせることで、堅牢なプログラミングが可能になります。
事前条件は、assertタグのcondition属性に記述します。
condition属性がfalseと評価された場合、throwタグと同様に例外が発生します。
messageCode属性、args属性を設定することも可能です。
validateタグにassertタグを含めることで、本体のロジックが呼ばれる前に、
事前条件をチェックすることができます。
次のFlowletは、引数のnameが設定されていることを事前条件としてチェックしています。

#### examples.org.seasar.nazuna.PreConditionFlowlet

    <flowlet>
        <input>
            <arg name="name" className="java.lang.String"/>
        </input>
        <validate>
            <assert condition="name is not null">new java.lang.IllegalArgumentException('name')</assert>
        </validate>
        <stmt>out.println('Hello ' || name)</stmt>
    </flowlet>

    package examples.org.seasar.nazuna;

    import org.seasar.nazuna.Nazuna;

    public class PreConditionFlowletClient {

        private static final String FLOWLET_NAME =
            "examples.org.seasar.nazuna.PreConditionFlowlet";

        public static void main(String[] args) {
            try {
                Nazuna.execute(FLOWLET_NAME, "Nazuna");
                System.out.println("illegal argument");
                try {
                    Nazuna.execute(FLOWLET_NAME);
                } catch (Exception ex) {
                    System.out.println(ex);
                }
            } catch (SeasarException ex) {
                ex.printStackTrace();
            }
        }
    }

実行結果は、

    Hello Nazuna
    illegal argument
    ERROR 2003-12-31 16:48:08,947 [main]
    [ESSR0347]Exception ocurred at
      examples.org.seasar.nazuna.PreConditionFlowlet:/flowlet[1]/validate[1]/assert[1],
      because java.lang.IllegalArgumentException: name
    java.lang.IllegalArgumentException: name

になります。
事後条件は、JUnitなどのテストツールでチェックすることを推奨します。

#### 自動トランザクション制御

flowletタグのtransAttribute属性を設定することで、
Nazunaにトランザクション制御を任せることもできます