CodeZine(コードジン)

特集ページ一覧

IRISのインターオペラビリティ機能を使いこなそう(前編)

InterSystems IRISでシンプルに開発するIoTアプリケーション 第5回

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

目次

ビジネス・オペレーションの定義

 連載の以前の回で、ビジネス・オペレーションについて、

プロダクション内の他のコンポーネントからメッセージを受け取り、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つのビジネス・オペレーションの定義ができましたので、コンパイルしてください。


  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 堀田 稔(インターシステムズジャパン)(ホリタ ミノル)

    SEマネージャー。 1992年大阪大学基礎工学部情報工学科卒。同年日本ディジタルイクイップメント(株)入社。電気通信など様々な業界向けプロジェクトにシステムエンジニアとして携わる。1996年InterSystems Data Platform製品の日本語版開発プロジェクトに従事し、同製品の販売・サ...

バックナンバー

連載:InterSystems IRISでシンプルに開発するIoTアプリケーション
All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5