4D v16

SPベースのサービス (例題)

ホーム

 
4D v16
SPベースのサービス (例題)

SPベースのサービス (例題)  


 

 

SPベースの読み込み (例題)で説明している例では、ストアドプロシージャは、データ読み込み処理が要求されるたびに開始され、終了されています。次の例では、ストアドプロシージャはサーバデータベースが起動されると自動的に開始され、サーバデータベースに接続している任意の4Dから随時に終了する、または再開することができます。ストアドプロシージャは実行されるとすぐに、データベースに接続しているクライアントから送られる複数の要求に対して、非同期的に応答することができるようになります。

SPベースの読み込み (例題)の節では、4D Server で提供される既存のサービスを飛躍的に最適化する方法について説明していますが、この例ではすべての4Dクライアントマシンで使用できる、新しいサービスやカスタムサービスを実現する方法について説明します。さらにこの例は、独自のサービスを実現するためのテンプレートとしても使用することができます。

ストアドプロシージャはOn Server Startupデータベースメソッドによって自動的に開始されます:

  ` On Server Startup Database Method
 START SP SERVICES

On Server Startupデータベースメソッドが、SP SERVICESプロジェクトメソッドをストアドプロシージャとして開始するため、実際にクライアントがサーバデータベースに接続しているかどうかに関わらず、4D Server でデータベースが開かれるとすぐにSP SERVICESが実行されます。次の図では、クライアントがまだ接続していない状態で、ストアドプロシージャが実行されている様子が4D Server の管理ウィンドウに表示されています。

START SP SERVICES プロジェクトメソッドは以下のとおりです。:

  ` START SP SERVICES プロジェクトメソッド
 <>vlSPServices:=Execute on server("SP SERVICES";32*1024;"SP SERVICES";*)

Execute on serverコマンドはサーバマシンから呼ばれたときはNew processと同様に動作するので、同じメソッド (START SP SERVICES) をサーバマシンおよびクライアントマシンから使用して、ストアドプロシージャとしてSP SERVICESメソッドをサーバマシン上で実行できます。

STOP SP SERVICESプロジェクトメソッドはSP SERVICESプロジェクトメソッドに停止するよう通知します。

  ` STOP SP SERVICES Project Method
 SET PROCESS VARIABLE(<>vlSPServices;vbStopSPServices;True)

SP SERVICESプロジェクトメソッドが開始されると、vbStopSPServicesプロセス変数がFalseに設定され、このブール変数がTrueになるまでループします。コマンドSET PROCESS VARIABLEを使用して、サーバあるいはクライアント上で実行されているユーザプロセスからvbStopSPServices変数の値を変更し、ストアドプロシージャを停止させられます。

ストアドプロシージャは、任意の時間に任意の順序で非同期的にクライアントのリクエストを受信し、応答できる必要があります。この通信を保証する簡単な方法はテーブルを使用することです。

[SP Requests] テーブルには、次のフィールドが含まれています:

  • [SP Requests]reqIDは、Sequence numberコマンドを使用して設定されます。このフィールドによって各リクエストを識別します。
  • [SP Requests]reqTypeはリクエストのタイプを示します。
  • [SP Requests]reqStatusは次の値のうちいずれかになります:
説明
1リクエストは送られたが、まだ処理されていない。
0リクエストは正常に処理された。
< 0リクエストは処理されたが、エラーが発生した。

Note: これらの値は、この例題のため任意に選ばれたものであり、4D から与えられた値ではありません。

  • [SP Requests]reqDataは、リクエストデータを格納しているBLOB です。リクエスト元から送られたデータやストアドプロシージャからリクエスト元に返されるデータが含まれています。
  • [SP Requests]reqParamsには、オプションとしてリクエスト元がストアドプロシージャに送った引数の値が含まれています。

クライアントプロセスとストアドプロシージャの間の通信はGET PROCESS VARIABLESET PROCESS VARIABLEVARIABLE TO VARIABLEコマンドを使用して実現できます。SPベースの読み込み (例題)の節や、前述のSTOP SP SERVICESプロジェクトメソッドで使用したソリューションがこの例です。

今回の場合は、ストアドプロシージャがさまざまな量のデータを送受信できるようにシステムが設定されていなければなりません。テキスト配列やピクチャ配列等の配列を使用することもできますが、次の2つの理由からテーブルを使用します:

  • レコードを使用してリクエストを処理するアルゴリズムの方が、より容易に実装できます。クライアントマシンからリクエストを送る処理は、テーブルにリクエストを追加する処理だけで構成されています。ストアドプロシージャ内からリクエストに応答する処理は、このリクエストレコードを修正する処理だけで構成されています。
  • リクエストはテーブルに格納されるため、ディスク上に保存されます。したがって、リクエストは (配列に格納されるデータの場合とは異なり) メモリには保持されず、リクエストのサイズが大きい場合でも問題にはなりません。

Client post request プロジェクトメソッドは、リクエストを送るための汎用的なメソッドです:

  ` Client post request プロジェクトメソッド
  ` Client post request ( String { ; Text } ) -> Long
  ` Client post request ( Request type { ; Parameters } ) -> Request ID
 CREATE RECORD([SP Requests])
 [SP Requests]reqID:=Sequence number([SP Requests])
 [SP Requests]reqType:=$1
 [SP Requests]reqStatus:=1
 If(Count parameters>=2)
    [SP Requests]reqParams:=$2
 End if
 SAVE RECORD([SP Requests])
 $0:=[SP Requests]reqID

このメソッドからリクエストID 番号が返されますが、Sequence numberコマンドを使用することにより、この番号は必ずユニークになります。レコードが[SP Requests]テーブルに追加された後、クライアントはフィールド[SP Requests]reqStatus を調べ、ストアドプロシージャが完全にリクエストを処理するまで待機します。

Client get resultプロジェクトメソッドは、リクエストステータスを調べるための汎用的なメソッドです。前述したように、[SP Requets]redStatusフィールドが1以外の値になるとすぐに、クライアントはストアドプロシージャがリクエストを処理したことが (成功しても失敗しても) 分かります。

  ` Client get result プロジェクトメソッド
  ` Client get result ( Long ; ->BLOB {; Long } ) -> Long
  ` Client get result ( Request ID ; ->Data {; Delay } ) -> Error Code
 C_LONGINT($0;$1;$vlDelay)
 $0:=1
 $vlDelay:=0
 If(Count parameters>=3)
    $vlDelay:=$3
 End if
 READ ONLY([SP Requests])
 Repeat
    QUERY([SP Requests];[SP Requests]reqID=$1)
    If(Records in selection([SP Requests])>0)
       If([SP Requests]reqStatus?#?1)
          $2->:=[SP Requests]reqData
          READ WRITE([SP Requests])
          While(Locked([SP Requests]))
             DELAY PROCESS(Current process;$vlDelay)
             LOAD RECORD([SP Requests])
          End while
          DELETE RECORD([SP Requests])
          $0:=[SP Requests]reqStatus
       End if
    Else
  ` リクエストレコードが失われた!
  ` これは発生すべきではないが、とにかくerrorを-2に設定 (任意の値)
       $0:=-2
    End if
  ` リクエストはまだ処理されていない
    If($0=1)
       WAITING LOOP($vlDelay)
    End if
 Until($0?#?1)
 READ ONLY([SP Requests])

リクエストがストアドプロシージャにより正常に処理された場合、このメソッドはレコードからBLOB へ結果をコピーします (ある場合)。BLOB へのポインタは引数として渡されます。次に、呼び出し元であるメソッドでリクエストタイプに応じ、BLOB データが解析されます。リクエストの処理が終了したら、[SP Requests]レコードの削除を行うのはクライアントである点に注意してください。

小さなWAITING LOOPプロジェクトメソッドは、指定したtick数が経過するまでループします:

  ` WAITING LOOP Project Method
  ` WAITING LOOP ( Long )
  ` WAITING LOOP ( Delay in ticks )
 C_LONGINT($1)
 $vlStartTicks:=Tickcount
 Repeat
    IDLE
 Until((Tickcount-$vlStartTicks)>=$1)

ReminderWAITING LOOP プロジェクトメソッドは、クライアントマシンのユーザ環境プロセスからリクエストされた場合でも、必要なだけ時間を待つために使用されています。

SP SERVICESプロジェクトメソッドは、サーバマシン上でストアドプロシージャとして実行されるメソッドです。疑似コードを次に示しますが、総体的なアーキテクチャは簡単です:

   “stop” 変数の初期化
   以下繰り返す
      [SP Requests]reqStatus フィールドが1であるリクエストを検索
      リクエストごとに
         リクエストのタイプに応じて、サブルーチンを呼び出し、
            [SP Requests]reqData フィールドに結果を格納する
         リクエストのステータスを変更し、処理の終了をクライアントに通知
      リクエストごとの繰り返しここまで
      再開始するまで少々の時間停止する
   “stop” 変数がTrueになるまで

以下は実際のコードです:

  ` SP SERVICES プロジェクトメソッド
  ` ストアドプロシージャの開始
 vbStopSPServices:=False
  ` ストアドプロシージャはテーブルに対し読み書きアクセスを必要としない
 READ ONLY(*)
  ` ただし[SP Requests] テーブルを除く
 READ WRITE([SP Requests])
 Repeat
  ` まだ処理していないリクエストを検索
    QUERY([SP Requests];[SP Requests]reqStatus=1)
  ` これらのリクエストをひとつづつ処理
    For($vlRecord;1;Records in selection([SP Requests]))
  ` リクエストレコードがロックされていれば、ロック解除まで待つ
       While(Locked([SP Requests]))
  ` 再試行まで1秒待つ
          DELAY PROCESS(Current process;60)
  ` 読み書きアクセスを試行
          LOAD RECORD([SP Requests])
       End while
  ` 処理が成功したと仮定する
       [SP Requests]reqStatus:=0
       Case of
          :([SP Requests]reqType="Server Information")
             SP DO SERVER INFORMATION
          :([SP Requests]reqType="Volume List")
             SP DO VOLUME LIST
          :([SP Requests]reqType="Browse Directory")
             SP DO BROWSE DIRECTORY([SP Requests]reqParams)
  ` ...
  ` 他のリクエストタイプをここに追加可能!
  ` ...
          Else
  ` 未知のリクエストタイプ, エラー -1を返す (任意の値)
             [SP Requests]reqStatus:=-1
       End case
  ` リクエストステータスが1でないようにする
  ` (サブルーチンが1にしてしまった場合)
       If([SP Requests]reqStatus=1)
          [SP Requests]reqStatus:=-3
       End if
  ` リクエストレコードを更新
       SAVE RECORD([SP Requests])
  ` 次の未処理レコードに移動
       NEXT RECORD([SP Requests])
    End for
  ` 最後に処理したレコードをアンロード
    UNLOAD RECORD([SP Requests])
  ` 再び処理を開始する前に1秒待つ
    DELAY PROCESS(Current process;60)
  ` 停止を指示されるまでループする
 Until(vbStopSPServices)

SP SERVICESプロジェクトメソッドは、データベースに新しいサービスを実現するためのテンプレートとして使用することができます。この節では、SP DO SERVER INFORMATIONサブルーチンおよびSP DO VOLUME LISTサブルーチンの詳細について説明します。SP DO BROWSE DIRECTORY ([SP Requests]reqParamsフィールドに納めて送られた引数を引数として取得するサブルーチン) の詳細については、このドキュメントでは説明されていません。

リクエストのタイプによってSP SERVICESプロジェクトメソッドは、結果データを[SP Requests]reqDataフィールドに保存する処理を行うサブルーチンを呼び出します。レコードの保存やリクエストステータスの変更は、SP SERVICESプロジェクトメソッドによって実行されます。

次に示すのはSP DO SERVER INFORMATIONサブルーチンです。このサブルーチンはサーバ関連の情報をBLOB に保存します。別のプロジェクトメソッドを使用して、クライアントマシン上でBLOB データを取り出します。

  ` SP DO SERVER INFORMATION プロジェクトメソッド
 TEXT TO BLOB(Application version(*);[SP Requests]reqData;UTF8 C string)
 TEXT TO BLOB(Structure file;[SP Requests]reqData;UTF8 C string;*)
 TEXT TO BLOB(Data file;[SP Requests]reqData;UTF8 C string;*)
 PLATFORM PROPERTIES($vlPlatform;$vlSystem;$vlMachine)
 VARIABLE TO BLOB($vlPlatform;[SP Requests]reqData;*)
 VARIABLE TO BLOB($vlSystem;[SP Requests]reqData;*)
 VARIABLE TO BLOB($vlMachine;[SP Requests]reqData;*)

次に示すのはSP DO VOLUME LISTサブルーチンです。このサブルーチンは、ボリューム関連の情報をBLOB に保存します。別のプロジェクトメソッドを使用して、クライアントマシン上でBLOB データを取り出します。

  ` SP DO VOLUME LIST プロジェクトメソッド
 VOLUME LIST($asVName)
 $vlSize:=Size of array($asVName)
 REAL($arVSize;$vlSize)
 REAL($arVUsedSpace;$vlSize)
 REAL($arVFreeSpace;$vlSize)
 For($vlElem;1;$vlSize)
    VOLUME ATTRIBUTES($asVName{$vlElem};$arVSize{$vlElem};$arVUsedSpace{$vlElem}
    ;$arVFreeSpace{$vlELem})
 End for
 VARIABLE TO BLOB($asVName;[SP Requests]reqData)
 VARIABLE TO BLOB($arVSize;[SP Requests]reqData;*)
 VARIABLE TO BLOB($arVUsedSpace;[SP Requests]reqData;*)
 VARIABLE TO BLOB($arVFreeSpace;[SP Requests]reqData;*)

汎用的なClient post requestClient get resultプロジェクトメソッドを使用して、M_SERVER_INFORMATIONプロジェクトメソッドはストアドプロシージャより返されたサーバ情報をクライアントマシン上に表示します。このメソッドは、メニューに割り当てる、あるいはボタンのオブジェクトメソッドで呼び出してもいいでしょう。

  ` M_SERVER_INFORMATION
 C_BLOB(vxData)
 C_LONGINT($vlReqID;$vlErrCode;$vlOffset)
  ` リクエストを送信
 $vlReqID:=Client post request("Server Information")
  ` リクエストステータスを見て、結果を取得
 $vlErrCode:=Client get result($vlReqID;->vxData;60)
  ` リクエストが正しく処理されていれば、結果を表示
 If($vlErrCode=0)
  ` BLOBから情報を取り出し
    $vlOffset:=0
    vsServerVersion:=BLOB to text(vxData;UTF8 C string;$vlOffset)
    vsStructureFile:=BLOB to text(vxData;UTF8 C string;$vlOffset)
    vsDataFile:=BLOB to text(vxData;UTF8 C string;$vlOffset)
    BLOB TO VARIABLE(vxData;$vlPlatform;$vlOffset)
    BLOB TO VARIABLE(vxData;$vlSystem;$vlOffset)
    BLOB TO VARIABLE(vxData;$vlMachine;$vlOffset)
  ` プラットフォームプロパティを解析
    vs4DPlatform:="Unknown 4D Server Version"
    vsSystem:="Unknown System Version"
    vsMachine:="Unknown Machine"
  `...
  ` $vlSystem と $vlMachineを取得するコードをここに記述
  ` (PLATFORM PROPERTIES コマンドの例題参照)
  ` ...
  ` 結果を表示
    DIALOG([SP Requests];"SERVER INFORMATION")
 Else
    ALERT("Request error "+String($vlErrCode))
 End if
  ` BLOBは必要ない
 CLEAR VARIABLE(vxData)

以下は実行された[SP Requests];"SERVER INFORMATION"フォームです:

汎用的なClient post requestClient get resultプロジェクトメソッドを使用して、M_SERVER_INFORMATIONプロジェクトメソッドはストアドプロシージャより返されたボリューム一覧をクライアントマシン上に表示します。このメソッドをメニューに割り当てたり、あるいはボタンのオブジェクトメソッドで呼び出してもいいでしょう:

  ` M_SERVER_VOLUMES
 C_BLOB(vxData)
  ` リクエストを送信
 $vlReqID:=Client post request("Volume List")
  ` リクエストステータスを見て、結果を取得
 $vlErrCode:=Client get result($vlReqID;->vxData;120)
  ` リクエストが正しく処理されていれば、結果を表示
 If($vlErrCode=0)
  ` BLOBから情報を取り出し
    $vlOffset:=0
    BLOB TO VARIABLE(vxData;asVName;$vlOffset)
    BLOB TO VARIABLE(vxData;arVSize;$vlOffset)
    BLOB TO VARIABLE(vxData;arVUsedSpace;$vlOffset)
    BLOB TO VARIABLE(vxData;arVFreeSpace;$vlOffset)
    For($vlElem;1;Size of array(arVSize))
  ` バイトをMBに変換
       arVSize{$vlElem}:=arVSize{$vlElem}/1048576
       arVUsedSpace{$vlElem}:=arVUsedSpace{$vlElem}/1048576
       arVFreeSpace{$vlElem}:=arVFreeSpace{$vlElem}/1048576
    End for
  ` 結果を表示
    DIALOG([SP Requests];"VOLUME LIST")
 Else
    ALERT("Request error "+String($vlErrCode))
 End if
  ` BLOBは必要ない
 CLEAR VARIABLE(vxData)

以下は実行された[SP Requests];"VOLUME LIST"フォームです:



参照 

SPベースの読み込み (例題)
ストアドプロシージャ

 
プロパティ 

プロダクト: 4D
テーマ: 4D Serverと4Dランゲージ

 
履歴 

 
ARTICLE USAGE

4D Server ( 4D v16)