Java ラッパー・クラス
- 生成済みのプログラム。
- そのプログラム内のパラメーターとして宣言される各レコードまたはフォーム。プログラムが、入力レコードを持つメインプログラムである場合は、入力レコードに渡される内容を表すためにラッパー・クラスが生成されます。
- フレキシブル・レコードによって直接格納される各レコードまたは動的配列。
- パラメーターとして宣言される各動的配列。動的配列が構造化レコードの配列である場合は、動的配列クラスのクラスが構造化レコード自身のクラスに追加されます。
- 以下の特性の各構造化フィールド
- ラッパー・クラスが生成される構造化レコードまたはフォームのいずれかの中にある
- 少なくとも 1 つの従属構造化フィールド (すなわち、副構造化) がある
- 配列である (この場合は副構造配列)
副構造配列がある構造化レコード・パーツの例を以下に示します。
Record myPart type basicRecord 10 MyTopStructure CHAR(20)[5]; 20 MyStructureField01 CHAR(10); 20 MyStructureField02 CHAR(10); end
後述の説明では、プログラム・ラッパー・クラス、パラメーター・ラッパー・クラス、動的配列ラッパー・クラス、および副構造フィールド配列ラッパー・クラスとしての指定プログラムのラッパー・クラスについて言及します。
EGL は、パラメーター・ラッパー・クラス、動的配列ラッパー・クラス、または副構造フィールド配列ラッパー・クラスのそれぞれに対して BeanInfo クラスを生成します。 BeanInfo クラスでは、関連するラッパー・クラスを Java 準拠の Java Bean として使用できます。 ただし、BeanInfo クラスとやり取りすることはほとんどありません。
ラッパーを生成する場合、呼び出し先プログラムのパラメーター・リストでは BLOB、CLOB、Dictionary、ArrayDictionary、または非構造化レコードのタイプのパラメーターは組み込むことができません。
ラッパー・クラスの使用方法の概要
- オプションで、以下のように PowerServer または SharedResourcePowerServer 型のクラスをインスタンス化し、ネイティブの Java コードと生成済みプログラムとの間のデータ変換などのミドルウェア・サービスを提供します。
import com.ibm.javart.JavartException; import com.ibm.javart.calls.*; public class MyNativeClass { /* declare a variable for middleware */ PowerServer powerServer = null; powerServer = new PowerServerImpl(); }SharedResourcePowerServer オブジェクトによって提供される機能は、PowerServer オブジェクトによって提供される機能より広範囲です。 前者の詳細については、『SharedResourcePowerServer』を参照してください。
PowerServer オブジェクトが指定されていない場合は、EGL ランタイムが自動的に指定します。
- 以下を実行するプログラム・ラッパー・クラスをインスタンス化します。
- 動的配列などのデータ構造を (ある場合は) 割り振る
- 結果として生成済みプログラムにアクセスするメソッドへのアクセスを提供する
コンストラクターの呼び出しには、以下のミドルウェア・オブジェクトが含まれることがあります。// use of a PowerServer object is optional myProgram = new MyprogramWrapper(PowerServer);ラッパー・オブジェクトの呼び出し時、またはラッパー・オブジェクト・メソッド setPowerServer を呼び出すことにより、PowerServer オブジェクトを指定できます。
- 以下のようにパラメーター・ラッパー・クラスに基づいた変数を宣言します。
Mypart myParm = myProgram.getMyParm(); Mypart2 myParm2 = myProgram.getMyParm2();ユーザーのプログラムに動的配列であるパラメーターがある場合は、以下のようにそれぞれ動的配列ラッパー・クラスに基づいた追加の変数を宣言します。myRecArrayVar myParm3 = myProgram.getMyParm3();動的配列の扱いについて詳しくは、動的配列ラッパー・クラスを参照してください。
- ほとんどの場合は (上記のステップにあるように)、プログラム・ラッパー・オブジェクトに割り当てられたメモリーの参照および変更にはパラメーター変数を使用します。以下に、EGL メインプログラムの入力レコード (この場合は名前 MyRecord) にデータを取り込むために Java レコード (この場合は、名前 inputValue) を使用する別の例を示します。
myProgram.setMyRecord(inputValue); - 以下の場合にのみ、ユーザー ID およびパスワードを設定します。
- Java ラッパーが iSeries Toolbox for Java の方法で iSeries ベースのプログラムにアクセスする場合
- 生成済みプログラムが、リモート・アクセスを認証した CICS® for z/OS® 領域で実行される場合
このユーザー ID およびパスワードは、データベース・アクセスには使用されません。
ユーザー ID およびパスワードは、以下の例のように、プログラム・オブジェクトの callOptions 変数を使用して設定および確認します。myProgram.callOptions.setUserID("myID"); myProgram.callOptions.setPassword("myWord"); myUserID = myProgram.callOptions.getUserID(); myPassword = myProgram.callOptions.getPassword(); - 呼び出されるプログラムが EGL メインプログラムである場合のみ使用可能な以下の機能を使用することを検討してください。
- 以下の例に示すように、使用する呼び出し側プログラムのデータベース接続を指定します。
// Connect to the database Connection con = DriverManager.getConnection( "jdbc:db2://host:50000/db", "user", "pwd" ); // Turn off auto-commit mode to enable transactions con.setAutoCommit( false ); // Create the wrapper and give it the connection MWrapper mw = new MWrapper(); mw.addConnection( con, "con1" ); // Run the program mw.execute(); // Commit the work and clean up mw.getPowerServer().commit(); mw.getPowerServer().close(); con.close(); - 以下の例に示すように、戻り値 (sysVar.returnCode の値) にアクセスします。
int returnValue = myProgram.returnCode();
- 以下の例に示すように、使用する呼び出し側プログラムのデータベース接続を指定します。
- 例えば以下のようにプログラム・ラッパー・オブジェクトの実行メソッドを呼び出すことによって、生成済みプログラムにアクセスします。
myProgram.execute();別の代替方法は、呼び出しメソッドを使用することです。この場合、メソッド呼び出しで引数を指定します。以下に、execute の 2 番目の使用例を示します。myProgram.setParm1( 2 ); myProgram.setParm2( "sell" ); myProgram.execute();以下に、呼び出しメソッドの同等の呼び出しを示します。myProgram.call( 2, "sell" ); - 以下の状態の場合にのみ、ミドルウェア・オブジェクトを使用してデータベース・トランザクション・コントロールを設定します。
- プログラム・ラッパー・オブジェクトが CICS for z/OS 上の生成済みプログラムにアクセスするか、または IBM® Toolbox for Java の方法で iSeries ベースの COBOL プログラムにアクセスする場合。 後のケースでは、呼び出しの remoteComType の値は JAVA400 または JAVA400J2C です。
- ラッパー・クラスの生成に使用されるリンケージ・オプション・パーツで、データベースの作業単位がクライアント (このケースではラッパー) の制御下にあると指定した場合。 詳しくは、callLink 要素にある luwControl のリファレンスを参照してください。
データベースの作業単位がクライアントの制御下にある場合、以下のように、処理にはミドルウェア・オブジェクトのコミットおよびロールバックの各メソッドの使用が含まれます。powerServer.commit(); powerServer.rollBack();単一の PowerServer オブジェクトを使用する場合、EGL ランタイムは、初回の接続で行った変更をコミットできますが、2 回目の接続で行った変更をコミットすると問題が発生して失敗することがあります。コミットは、すべてのリソースがコミットされるかどのリソースもコミットされないような 2 フェーズ・コミットではなく 1 フェーズ・コミットであるため、失敗後にデータは矛盾した状態のままになります。
- ミドルウェア・オブジェクトを閉じます。明示的に宣言しなかった場合は、前の例に示されているように、ラッパー固有のメソッド getPowerServer().close() を使用します。
EGL 実行単位を終了して、ガーベッジ・コレクションを実行できるようにするには、ミドルウェア・オブジェクトを閉じます。
if ( powerServer != null ) { try { powerServer.close(); powerServer = null; } catch ( JavartException error ) { System.out.println( "Error closing middleware" + error.getMessage() ); System.exit( 8 ); } }
プログラム・ラッパー・クラス
プログラム・ラッパー・クラスには、生成済みプログラム内の各パラメーターごとにプライベート・インスタンス変数が含まれます。 パラメーターがレコードまたはフォームである場合、変数は、関連するパラメーター・ラッパー・クラスのインスタンスを参照します。 そのパラメーターがデータ項目パーツに基づいている場合、変数の型はプリミティブ Java です。
このヘルプ・ページの最後にある表には、EGL と Java の各型の間の変換が説明されています。
- 各パラメーターごとの get メソッドおよび set メソッド。名前の形式を以下に示します。
purposeParmname()- purpose
- ワード get または set
- Parmname
- データ項目、レコード、またはフォームの名前。最初の文字は大文字であり、その他の文字の表記はJava ラッパー・クラスの命名規則に示されている命名規則によって決まります。
- プログラムを呼び出す execute メソッド。 このメソッドは、その呼び出しの引数として渡されるデータがプログラム・ラッパー・オブジェクトに割り振られたメモリー内にある場合に使用します。
- パラメーター・ラッパー・オブジェクト、動的配列ラッパー・オブジェクト、およびプリミティブ型にメモリーを割り振る
- 割り振ったメモリーに値を割り当てる
- execute メソッドではなく、プログラム・ラッパー・オブジェクトの call メソッドを呼び出してプログラムにそれらの値を渡す
- 呼び出しのリンケージ・オプションが生成時に設定されるように Java ラッパーを生成した場合、callOptions 変数にはリンケージ情報が格納されます。 リンケージ・オプションが設定される場合の詳細については、callLink 要素にある remoteBind を参照してください。
- 呼び出しのリンケージ・オプションが実行時に設定されるように Java ラッパーを生成した場合、callOptions 変数にはリンケージ・プロパティー・ファイルの名前が格納されます。 ファイル名は LO.properties です。 LO は生成に使用されたリンケージ・オプション・パーツの名前です。
- いずれの場合も、callOptions 変数は、ユーザー ID およびパスワードを設定または取得するために以下のようなメソッドを提供します。
setPassword(passWord) setUserid(userid) getPassword() getUserid()このユーザー ID およびパスワードは、callLink エレメントの remoteComType プロパティーを以下のいずれかの値に設定した場合に使用されます。- CICSECI
- CICSJ2C
- JAVA400
- JAVA400J2C
- returnCode() は、sysVar.returnCode の値を戻します。
- addConnection() は、EGL メインプログラムが使用する JDBC 接続オブジェクトを指定します。addConnection() の各呼び出しによって、実行単位の現行接続として接続が割り当てられます。
実行単位は、以前に指定された接続がある場合は、その接続を使用できます。ただし、実行単位が特定の接続を閉じると、接続は解放され、再オープンできません。その最後の制約事項は、EGL プログラムで閉じる場合、あるいは (前のセクションで示したように) powerServer.close() を呼び出すことで閉じる場合に当てはまります。
addConnection() は、最大で 3 つの引数を指定して呼び出しますが、最後の引数はオプションです。以下に、メソッド・シグニチャーを示します。public void addConnection (java.sql.Connection con, java.lang.String name, int disconnectOption) throws java.lang.NullPointerException, java.lang.IllegalArgumentException, com.ibm.javart.JavartExceptionパラメーターは以下のとおりです。- con (java.sql.Connection 型) は、ビルド記述子オプション DBMS で指定されたデータベース・タイプへの接続です。
- name (java.lang.String 型) は接続名です。メインプログラムは、システム関数 sqlLib.beginDatabaseTransaction()、sqlLib.defineDatabaseAlias()、sqlLib.disconnect()、および sqlLib.setCurrentDatabase() の呼び出しでその名前を使用します。
- disconnectOption (int 型) は、以下のいずれかの定数で指定される接続オプションです。
- DISCONNECT_NEVER はデフォルト値であり、Java コード呼び出し powerServer.close() を呼び出した場合でも、接続を閉じようとしても効果がないことを示します。
powerServer.close() コミットは機能し、EGL 実行単位を閉じます。その他すべての切断オプションでは、実行単位を終了すると、開いているすべての接続が閉じます。
- DISCONNECT_AUTOMATIC は、ロールバック後、コミット後、またはメインプログラムが sqlLib.disconnect() または sqlLib.disconnectAll() を呼び出した後で接続が閉じることを示します。
- DISCONNECT_CONDITIONAL は、ロールバック後、接続によって作成された開いているいずれかの結果セットで HOLD オプションが有効になっていない場合のコミット後、またはメインプログラムが sqlLib.disconnect() または sqlLib.disconnectAll() を呼び出した後で、接続が閉じることを示します。
- DISCONNECT_EXPLICIT は、ロールバックまたはコミット後に接続は閉じないが、メインプログラムが sqlLib.disconnect() または sqlLib.disconnectAll() を呼び出した後では接続が閉じることを示します。
以前の値のうち、最初の値を除くすべての値が、システム関数 sqlLib.connect() の呼び出し時に指定できる値と同じ意味を持ちます。 EGL 列挙 egl.io.sql.DisconnectKind の同等の値は、DisconnectKind.automatic、DisconnectKind.conditional、DisconnectKind.explicit です。DISCONNECT_NEVER と同等の値は、sqlLib.connect() の呼び出し時には無効です。
- DISCONNECT_NEVER はデフォルト値であり、Java コード呼び出し powerServer.close() を呼び出した場合でも、接続を閉じようとしても効果がないことを示します。
- ネイティブ・コードがプリミティブ型のパラメーターで set メソッドを呼び出す
- 生成済みプログラムがプリミティブ型のパラメーターに変更データを戻す
PropertyChange イベントは、Oracle の JavaBean 仕様で説明されています。
パラメーター・ラッパー・クラスのセット
Mypart myRecWrapperObject = myProgram.getMyrecord();
このケースでは、プログラム・ラッパー・オブジェクトによって割り振られたメモリーを使用しています。
また、プログラム・オブジェクトの (execute メソッドではなく) call メソッドを呼び出す場合には、必要に応じてパラメーター・ラッパー・クラスをメモリーの宣言にも使用できます。
- パラメーターの低レベル構造化フィールドのそれぞれに対するが、配列でもなく副構造配列でもない構造化フィールドに対してのみの、Java プリミティブ型の 1 つの変数
- 配列ではあるが副構造ではない各 EGL 構造化フィールドに対する Java プリミティブ型の 1 つの配列
- 副構造配列にそれ自身が入っていない各副構造配列に対する内部配列クラスのオブジェクト。 内部クラスには、従属の副構造配列を表す内部クラスをネストできます。
- get メソッドおよび set メソッドのセットにより、各インスタンス変数を取得および設定できます。
それぞれのメソッド名の形式を以下に示します。
purposesiName()- purpose
- ワード get または set。
- siName
- 構造化フィールドの名前。
最初の文字は大文字であり、その他の文字の表記はJava ラッパー・クラスの命名規則に示されている命名規則によって決まります。
注: 充てん文字として宣言した構造化フィールドはプログラム呼び出しに含まれますが、配列ラッパー・クラスにはそれらの構造化フィールドに対する public get メソッドまたは set メソッドは含まれません。
- メソッド equals により、同じクラスの別のオブジェクトに格納された値がパラメーター・ラッパー・オブジェクトに格納された値と同一であるかどうかを判別できます。 このメソッドでは、そのクラスおよび値が同一である場合にのみ true を戻します。
- メソッド addPropertyChangeListener は、ユーザーのプログラムで Java プリミティブ型の値変更の通知が必要な場合に呼び出されます。
- get メソッドおよび set メソッドの 2 番目のセットにより、SQL レコード・パラメーター内の各構造化フィールドごとにヌル標識を取得および設定できます。
これらの各メソッド名の形式を以下に示します。
purposesiNameNullIndicator()- purpose
- ワード get または set。
- siName
- 構造化フィールドの名前。 最初の文字は大文字であり、その他の文字の表記はJava ラッパー・クラスの命名規則に示されている命名規則によって決まります。
副構造フィールド配列ラッパー・クラスのセット
- 配列の低レベル構造化フィールドのそれぞれに対するが、配列でもなく副構造配列でもない構造化フィールドに対してのみの、Java プリミティブ型の 1 つの変数
- 配列ではあるが副構造ではない各 EGL 構造化フィールドに対する Java プリミティブ型の 1 つの配列
- 副構造配列にそれ自身が入っていない各副構造配列に対する内部副構造フィールド配列ラッパー・クラスのオブジェクト。 内部クラスには、従属の副構造配列を表す内部クラスをネストできます。
- 各インスタンス変数に対する get メソッドおよび set メソッドのセット
注: 匿名充てん文字として宣言した構造化フィールドはプログラム呼び出しに使用されますが、副構造フィールド配列ラッパー・クラスにはそれらの構造化フィールドに対する public get メソッドまたは set メソッドは含まれません。
- メソッド equals により、同じクラスの別のオブジェクトに格納された値が副構造フィールド配列ラッパー・オブジェクトに格納された値と同一であるかどうかを判別できます。 このメソッドでは、そのクラスおよび値が同一である場合にのみ true を戻します。
- ユーザーのプログラムで Java プリミティブ型の値変更の通知が必要な場合に使用される、addPropertyChangeListener メソッド
ParameterClassname.ArrayClassName
Record CompanyPart type basicRecord
10 Departments CHAR(20)[5];
20 CountryCode CHAR(10);
20 FunctionCode CHAR(10)[3];
30 FunctionCategory CHAR(4);
30 FunctionDetail CHAR(6);
end
パラメーター Company が CompanyPart に基づいている場合は、 内部クラスの名前として文字列 CompanyPart.Departments を使用します。
内部クラスの内部クラスにより、ドットの構文の使用が拡張されます。 この例では、シンボル CompanyPart.Departments.Functioncode を Departments の内部クラスの名前として使用します。
副構造フィールド配列ラッパー・クラスの命名方法について詳しくは、『Java ラッパー生成の出力』を参照してください。
動的配列ラッパー・クラス
Program myProgram(intParms int[], recParms MyRec[])
動的配列ラッパー・クラスの名前は、IntParmsArray および MyRecArray です。
IntParmsArray myIntArrayVar = myProgram.getIntParms();
MyRecArray myRecArrayVar = myProgram.getRecParms();
それぞれの動的配列用の変数を宣言した後、以下のような要素を追加します。
// Java プリミティブへの配列の追加は、
// 1 ステップのプロセスです
myIntArrayVar.add(new Integer(5));
// レコードまたはフォームの配列への追加には、
// 複数のステップが必要であり、このケースでは、
// 新規レコード・オブジェクトの割り振りで開始します
MyRec myLocalRec = (MyRec)myRecArrayVar.makeNewElement();
// 値を割り当てるステップはこの例に示されていませんが、
// 値を割り当てた後に、
// 配列にレコードを追加します
myRecArrayVar.add(myLocalRec);
// 次に、プログラムを実行します
myProgram.execute();
// プログラムが戻ると、
// 配列内の要素数を判別できます
int myIntArrayVarSize = myIntArrayVar.size();
// 整数配列の最初の要素を取得し、
// Integer オブジェクトにそれをキャストします
Integer firstIntElement = (Integer)myIntArrayVar.get(0);
// レコード配列の 2 番目の要素を取得し、
// MyRec オブジェクトにそれをキャストします
MyRec secondRecElement = (MyRec)myRecArrayVar.get(1);
上記の例で示されているように、EGL では宣言した変数を操作する複数のメソッドが提供されています。
| 動的配列クラスのメソッド | 用途 |
|---|---|
| add(int, Object) | int で指定された位置にオブジェクトを挿入する。 現在および後続の各要素を右にシフトする。 |
| add(Object) | 動的配列の最後にオブジェクトを追加する。 |
| addAll(ArrayList) | 動的配列の最後に ArrayList を追加する。 |
| get() | 配列内のすべての要素が格納された ArrayList オブジェクトを取得する |
| get(int) | int で指定された位置にある要素を取得する。 |
| makeNewElement() | 要素を動的配列に追加することなく、配列固有の型の新規要素を割り振り、その要素を取得する。 |
| maxSize() | 動的配列内の最大要素数 (実際の数ではない) を表す整数を取得する。 |
| remove(int) | int で指定された位置にある要素を除去する。 |
| set(ArrayList) | 指定した ArrayList を動的配列の置き換えとして使用する。 |
| set(int, Object) | 指定したオブジェクトを int で指定された位置にある要素の置き換えとして使用する。 |
| size() | 動的配列内にある要素数を取得する。 |
- get メソッドまたは set メソッドに無効なインデックスを指定した場合
- 配列内の各要素のクラスとは非互換のクラスの要素を追加 (または設定) した場合
- 配列の最大サイズの増加がサポートできないときに動的配列に要素を追加した場合、およびこの理由でメソッド addAll が失敗した場合、そのメソッドでは要素は追加されない
Java ラッパー・クラスの命名規則
- 名前がすべて大文字である場合は、すべての文字を小文字にする。
- 名前がキーワードである場合は、下線を前に付ける。
- 名前にハイフンまたは下線がある場合は、その文字を除去し、次の文字を大文字にする。
- 名前にドル記号 ($)、アットマーク (@)、またはポンド記号 (#) がある場合は、その各名前を 2 つの下線 (__) で置き換え、名前の前に下線 (_) を付ける。
- 名前がクラス名として使用されている場合は、最初の文字を大文字にする。
- ほとんどの場合、クラスの名前は、配列内の各要素の基本となるパーツ宣言 (データ項目、フォーム、およびレコード) の名前に基づきます。 例えば、レコード・パーツの名前が MyRec であり、配列宣言が recParms myRec[] である場合は、関連する動的配列ラッパー・クラスの名前は MyRecArray になります。
- 配列が関連するパーツ宣言のない宣言に基づいている場合、動的配列クラスの名前は配列名に基づきます。 例えば、配列宣言が intParms int[] である場合、関連する動的配列ラッパー・クラスの名前は IntParmsArray になります。
データ型の相互参照
下の表に、生成されるプログラム内の EGL プリミティブ型と、生成されるラッパー内の Java データ型の関係を示します。
| EGL プリミティブ型 | 文字または桁の長さ | 長さ (バイト) | 小数部 | Java データ型 | Java での最大精度 |
|---|---|---|---|---|---|
| BIN、SMALLINT | 4 | 2 | 0 | short | 4 |
| BIN、INT | 9 | 4 | 0 | int | 9 |
| BIN、BIGINT | 18 | 8 | 0 | long | 18 |
| BIN | 4 | 2 | >0 | float | 4 |
| BIN | 9 | 4 | >0 | double | 15 |
| BIN | 18 | 8 | >0 | double | 15 |
| BOOLEAN | 1 | 1 | NA | Boolean | NA |
| CHAR | 1-32767 | 2-32766 | NA | String | NA |
| DBCHAR | 1-16383 | 1-32767 | NA | String | NA |
| DATE | 8 | 8 | 0 | java.sql.Date | NA |
| DECIMAL、MONEY、PACF | 1 から 3 | 1 から 2 | 0 | short | 4 |
| DECIMAL、MONEY、PACF | 4 から 9 | 3 から 5 | 0 | int | 9 |
| DECIMAL、MONEY、PACF | 10 から 18 | 6 から 10 | 0 | long | 18 |
| DECIMAL、MONEY、PACF | 19-32 | 10-17 | 0 | java.math.BigInteger | 32 |
| DECIMAL、MONEY、PACF | 1 から 5 | 1 から 3 | >0 | float | 6 |
| DECIMAL、MONEY、PACF | 7 から 18 | 4 から 10 | >0 | double | 15 |
| DECIMAL、MONEY、PACF | 19-32 | 10-17 | >0 | java.math.BigDecimal | 32 |
| FLOAT | 18 | 8 | >0 | double | 15 |
| HEX | 2-75534 | 1-32767 | NA | byte[] | NA |
| INTERVAL (month- or second-span) | 1 から 21 | 2 から 22 | 0 | String | NA |
| MBCHAR | 1-32767 | 1-32767 | NA | String | NA |
| NUM、NUMC | 1 から 4 | 1 から 4 | 0 | short | 4 |
| NUM、NUMC | 5 から 9 | 5 から 9 | 0 | int | 9 |
| NUM、NUMC | 10 から 18 | 10 から 18 | 0 | long | 18 |
| NUM、NUMC | 19-32 | 19-32 | 0 | java.math.BigInteger | 32 |
| NUM、NUMC | 1 から 6 | 1 から 6 | >0 | float | 6 |
| NUM、NUMC | 7 から 18 | 7 から 18 | >0 | double | 15 |
| NUM、NUMC | 19-32 | 19-32 | >0 | java.math.BigDecimal | 32 |
| SMALLFLOAT | 9 | 4 | >0 | float | 6 |
| STRING | 1-16383 | 2-32766 | NA | String | NA |
| TIME | 6 | 6 | 0 | java.sql.Time | NA |
| TIMESTAMP | 1 から 20 | 1 から 20 | 0 | java.sql. Timestamp | NA |
| UNICODE | 1-16383 | 2-32766 | NA | String | NA |