それでは、さっそく使ってみましょう。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の型を指定します。
文字列の連結は、||を使います。
引数名は、英小字で始め、ドット(.)を含んではいけません。
<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タグのボディで、デフォルト値を指定することもできます。
<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のように、コンストラクタを使って、任意のオブジェクトを作成できます。
<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のプロパティにアクセスできます。
<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タグによって、条件分岐がすっきり書け、条件の判定も豊富な
関数や演算子を
使えることが、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タグが実行されます。
<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 init="初期変数の処理" condition="ループを繰り返すかどうかの条件"
next="次のループに入るときの処理">
ロジックタグ
ロジックタグ
</for>
init属性でi := 1のような初期変数の処理をすることができます。
i := 1; j := 1のようにセミコロンで区切って複数の処理を記述することもできます。
変数は、varタグであらかじめ宣言しておく必要があります。
condition属性では、i le 5のようなループを繰り返す条件を指定します。
<,>を含んだ比較は、比較演算子を参照してください。
next属性でi := i + 1のような次のループに入るときの処理をすることができます。
複数処理の記述は、initタグと同様です。
<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になります。
breakタグを使って、forタグの処理を途中で中断することもできます。
<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になります。
continueタグを使って、continueタグ以降の処理をスキップし、次のループに入ることもできます。
<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になります。
Javaと同様のwhile処理を行いたい場合は、forタグのinit属性、 next属性を省略します。
定数は、constタグを使って設定します。
name属性に設定した名前でアクセスします。
定数の名前は英大文字か数字にし、
複数の単語から構成される場合(例 CAR_NAME)は、単語と単語をアンダースコア(_)でつなぎます。
変数が、実行時に作成されるのに対し、
定数は、XMLのコンパイル時に作成されます。
定数に値を代入することはできません。
<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でpublic static finalとして定義した定数をincludeタグを使って
自分の定数として取り込むことができます。
インクルードするJavaのクラス名は、className属性で指定します。
package examples.org.seasar.nazuna;
public interface Constants {
int ONE = 1;
String A = "a";
}
<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のインスタンスメソッドは、変数名.メソッド名(引数, ...)で、 次のようにして呼び出すことができます。
<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側のオブジェクトをそのまま使えます。
FlowletからRuletを呼び出すこともできます。仕様は次のようになります。
executeRulet(Ruletのクラス名, 引数, ...)
引数の意味はNazuna.executeRuletメソッドと同様です。
例えば、examples.org.seasar.nazuna.HelloRuletを呼び出すには次のようにします。
<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からexecute()を使って他のFlowletを呼び出すこともできます。
仕様は次のようになります。
execute(Flowlet名, 引数, ...)
引数の意味はNazuna.executeメソッドと同様です。
例えば、examples.org.seasar.nazuna.ArgFlowletを呼び出すには次のようにします。
<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[]のように
配列にしたいクラス名の後に[]を指定します。
<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タグを使います。
今のところ、例外を捕捉する機能はありません。
<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])も知ることができます。
SeasarExceptionをthrowする場合は、messageCode属性とargs属性を使うこともできます。
<throw>new org.seasar.util.SeasarException('ESSR0028', 'a', 1)</throw>
の変わりに
<throw messageCode="ESSR0028" args="'a', 1"/>と省略して記述できます。
Flowletを呼び出すときに、Flowletが期待している引数の条件を事前条件といいます。
例をあげると次のようなものがあります。
<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になります。
flowletタグのtransAttribute属性を設定することで、
Nazunaにトランザクション制御を任せることもできます