ビジネス・オペレーションの定義
連載の以前の回で、ビジネス・オペレーションについて、
プロダクション内の他のコンポーネントからメッセージを受け取り、1つの機能を実行します。例えば、IRIS内部のデータベースにアクセスしたり、外部システムにデータを送信したりするなどの機能を実行します。
と説明しました。これから、ビジネス・オペレーションを具体的に定義していきましょう。
IRISに取り込まれた車載器の情報をリクエストとして受け取り、データベースを更新するためのビジネス・オペレーションDriveDemo.Operation.CarUpdateOperationを作成します。
まずは、定義の部分です。
Class DriveDemo.Operation.CarUpdateOperation Extends Ens.BusinessOperation [ ClassType = "", ProcedureBlock ] { Parameter INVOCATION = "Queue"; XData MessageMap { <MapItems> <MapItem MessageType="DriveDemo.Request.CarRegisterRequest"> <Method>RegisterCar</Method> </MapItem> <MapItem MessageType="DriveDemo.Request.CarUpdateRequest"> <Method>UpdateCar</Method> </MapItem> </MapItems> } … }
クラス宣言のExtends句で、Ens.BusinessOperationを継承しています。Ens.BusinessOperationクラスは、ビジネス・オペレーションに共通の機能を提供するIRISのクラスです。ビジネス・オペレーションを作成する場合は、必ずEns.BusinessOperationを継承することになります。
次に、XData MessageMapで始まるXMLデータを説明します。このデータはメッセージマップと呼ばれ、ビジネス・オペレーションが受信するリクエストの種類(クラス)と、その種類のリクエストを受信した際に起動されるメソッドの対応づけを定義します。
ここでは、
- DriveDemo.Request.CarRegisterRequest: RegisterCarメソッド
- DriveDemo.Request.CarUpdateRequest: UpdateCarメソッド
という対応が定義されています。
では、RegisterCarメソッドの定義を見てみましょう。
// 車のstartトッピックがきたら、そのCar IDに対しレコードを作成する Method RegisterCar( pRequest As DriveDemo.Request.CarRegisterRequest, Output pResponse As Ens.Response) As %Status { Set carid = pRequest.CarId Set ts = pRequest.StartTime // デモ目的のため、以前の同一Car IDのレコードを削除する &sql(DELETE FROM DriveDemo_Data.DriveRecord where CarId = :carid) &sql(DELETE FROM DriveDemo_Data.CarLatest where CarId = :carid) &sql(INSERT INTO DriveDemo_Data.CarLatest (CarId, Tm) values (:carid, :ts)) Quit $$$OK }
メソッドの引数には、
- pRequest: DriveDemo.Request.CarRegisterRequest
- pResponse: Ens.Response
が指定されています。pRequestは、このビジネス・オペレーションに送信されたリクエストが保持されています。先ほど紹介したメッセージマップより、このメソッドは、DriveDemo.Request.CarRegisterRequestクラスのメッセージが送られてきた時に呼び出されますので、引数のAs句にそのように型指定しています。
このメソッドでは、指定されたIDの車の情報を初期化します。初期化にはSQL文を使います。IRISのObjectScriptでは、&sql( )という構文でSQL文を記述することができます。この構文は、ObjectScriptのコードにSQLが埋め込まれる形をとるので、埋め込みSQLと呼ばれます。
このビジネス・オペレーションにはもう一つ、UpdateCarメソッドがあります。定義を次に示します。
Method UpdateCar( pRequest As DriveDemo.Request.CarUpdateRequest, Output pResponse As Ens.Response) As %Status { // 現在の運転情報を、CarLatestに記録 Set tCarId = pRequest.Data.CarId Set tRelativeTm = pRequest.Data.RelativeTm Set tLongitude = pRequest.Data.Longitude Set tLatitude = pRequest.Data.Latitude Set tAzimuth = pRequest.Data.Azimuth Set tSpeed = pRequest.Data.Speed Set tEngineRPM = pRequest.Data.EngineRPM Set tAccelPos = pRequest.Data.AccelPos Set tBrakeSW = pRequest.Data.BrakeSW Set tAcumDistance = pRequest.Data.AcumDistance Set tAcumFuel = pRequest.Data.AcumFuel Set tFuelInjection = pRequest.Data.FuelInjection Set taX = pRequest.Data.aX Set taY = pRequest.Data.aY Set taZ = pRequest.Data.aZ &sql(UPDATE DriveDemo_Data.CarLatest SET RelativeTm = :tRelativeTm, Longitude = :tLongitude, Latitude = :tLatitude, Azimuth = :tAzimuth, Speed = :tSpeed, EngineRPM = :tEngineRPM, AccelPos = :tAccelPos, BrakeSW = :tBrakeSW, AcumDistance = :tAcumDistance, AcumFuel = :tAcumFuel, FuelInjection = :tFuelInjection, aX = :taX, aY = :taY, aZ = :taZ where CarId = :tCarId) $$$TRACE("Car ID: "_tCarId_", Speed: "_tSpeed) Quit $$$OK }
メッセージマップの定義から、DriveDemo.Request.CarUpdateRequestを受信した時にこのメソッドが呼ばれますので、このメソッドの引数pRequestには、DriveDemo.Request.CarUpdateRequestのインスタンスが渡されます。
このメソッドは、リクエストから車載器データを取り出し、埋め込みSQLを使って車の最新情報(CarLatest)テーブルを更新します。
今回のアプリケーションにはもう一つビジネス・オペレーションがあります。車の運転状況をチェックし、イベントが発生していないかをチェックするDriveDemo.Operation.CheckDriveOperationです。
定義を次に示します。
Class DriveDemo.Operation.CheckDriveOperation Extends Ens.BusinessOperation [ ClassType = "", ProcedureBlock ] { Parameter INVOCATION = "Queue"; XData MessageMap { <MapItem MessageType="DriveDemo.Request.CheckDriveRequest"> <Method>CheckDrive</Method> </MapItem> } Method CheckDrive( pRequest As DriveDemo.Request.CheckDriveRequest, Output pResponse As DriveDemo.Response.CheckDriveResponse) As %Status { Set pResponse=##class(DriveDemo.Response.CheckDriveResponse).%New() Set pResponse.hasEvent = 0 Set pResponse.DrivingBehavior = ##class(DriveDemo.Data.DrivingBehavior).%New() Set tCarId = pRequest.CarId Set tRelTm = pRequest.RelativeTm &sql(SELECT AVG(speed) into :tAvgSpeed FROM DriveDemo_Data.DriveRecord WHERE CarId = :tCarId and RelativeTm BETWEEN :tRelTm - 5 AND :tRelTm) &sql(SELECT EngineRPM, aX, aY into :tEngineRPM, :taX, :taY FROM DriveDemo_Data.DriveRecord WHERE CarId = :tCarId and RelativeTm = :tRelTm) Set tMsgTxt = "" Set tDlm = "" if SQLCODE = 0 { if +$g(tAvgSpeed) > 100 { Set pResponse.hasEvent = 1 Set pResponse.DrivingBehavior.IsOverSpeed = 1 Set tMsgTxt = tMsgTxt_tDlm_"Average Speed: "_$fnumber(tAvgSpeed, "", 2)_" km/h" Set tDlm = " , " } if +$g(tEngineRPM) > 3000 { Set pResponse.hasEvent = 1 Set pResponse.DrivingBehavior.IsHighEngineRPM = 1 Set tMsgTxt = tMsgTxt_tDlm_"Engine RPM: "_tEngineRPM_" rpm" Set tDlm = " , " } if $zabs(+$g(taX)) > 300 { Set pResponse.hasEvent = 1 Set pResponse.DrivingBehavior.IsHighXG = 1 Set tMsgTxt = tMsgTxt_tDlm_"X acceleration: "_$fnumber((taX / 1000.0), "+", 3)_" G" Set tDlm = " , " } if $zabs(+$g(taY)) > 200 { Set pResponse.hasEvent = 1 Set pResponse.DrivingBehavior.IsHighYG = 1 Set tMsgTxt = tMsgTxt_tDlm_"Y acceleration: "_$fnumber((taY / 1000.0), "+", 3)_" G" Set tDlm = " , " } if pResponse.hasEvent = 1 { Set tMsgTxt = tMsgTxt_tDlm_"Car ID: "_pRequest.CarId } } Set pResponse.MessageText = tMsgTxt Quit $$$OK } }
他のビジネス・オペレーション同様、Extends句でEns.BusinessOperationクラスを継承しています。
DriveDemo.Operation.CheckDriveOperationのメッセージマップには一つだけエントリがあります。
- DriveDemo.Request.CheckDriveRequest: CheckDrive
CheckDriveメソッドを確認してみましょう。引数は、
- pRequest: DriveDemo.Request.CheckDriveRequest
- pResponse: DriveDemo.Response.CheckDriveResponse
となっています。レスポンスとしてDriveDemo.Response.CheckDriveResponseのインスタンスを返すようになっています。Outputキーワードは、その引数がメソッド内で変更され、呼び出し元に返すのに使用されることを指定します。
上に示したコード例の太字にした3行で、レスポンスのインスタンスを生成、初期化していることを確認してください。
以上で、2つのビジネス・オペレーションの定義ができましたので、コンパイルしてください。