Skip to main content

This is documentation for Caché & Ensemble. See the InterSystems IRIS version of this content.Opens in a new tab

For information on migrating to InterSystems IRISOpens in a new tab, see Why Migrate to InterSystems IRIS?

ファイル受信アダプタの使用法

この章では、ファイル受信アダプタ (EnsLib.File.InboundAdapterOpens in a new tab) の使用方法について説明します。この章は以下の節で構成されています。

Tip:

Ensemble では、このアダプタを使用する特殊なビジネス・サービス・クラスとユーザのニーズに適したビジネス・サービス・クラスの 1 つも提供されます。そのため、プログラミングの必要がありません。"Ensemble の紹介" の “接続オプション” の節を参照してください。

全般的な動作

EnsLib.File.InboundAdapterOpens in a new tab は、構成された場所でファイルを検索したり、入力を読み取ったり、入力をストリームとして関連するビジネス・サービスに送信したりします。ユーザが作成および構成するビジネス・サービスは、このストリームを使用してプロダクションの他の部分と通信します。受信ファイル・アダプタが構成された場所に複数のファイルを見つけた場合は、ファイルの最終変更時刻に基づいて、それが早いものから順番に処理します。ただし、アダプタは、時刻値の小数点以下の秒数は無視します。そのため、2 つ以上のファイルの変更日付と時刻が、時刻の小数点以下の秒数部分のみ異なる場合は、アダプタはこれらを任意の順序で処理します。

以下の図は、全体的なフローを示しています。

generated description: inbound

詳細は、以下のとおりです。

  1. アダプタは、構成されたデータ・ソースからの入力を検出するたびに、ビジネス・サービス・クラスの内部 ProcessInput() メソッドを呼び出して、ストリームを入力引数として渡します。

  2. ビジネス・サービス・クラスの内部 ProcessInput() メソッドが実行されます。このメソッドは、すべてのビジネス・サービスが必要とする内部情報の保持など、基本的な Ensemble タスクを実行します。ビジネス・サービス・クラスが継承するこのメソッドは、カスタマイズや上書きを行いません。

  3. 次に、ProcessInput() メソッドがカスタムの OnProcessInput() メソッドを呼び出し、ストリーム・オブジェクトを入力として渡します。このメソッドに関する要件については、後述の “OnProcessInput() メソッドの実装” で説明します。

応答メッセージは、同じパスを逆向きにたどります。

受信アダプタを使用するビジネス・サービスの作成

このアダプタをプロダクションで使用するには、ここに記載されているように新しいビジネス・サービスを作成します。後で、そのサービスをプロダクションに追加して構成します。存在しなければ、該当するメッセージ・クラスを作成する必要もあります。"Ensemble プロダクションの開発" の “Ensemble メッセージの定義” を参照してください。

ビジネス・サービス・クラスの基本要件を以下に列挙します。

以下の例は、必要となる一般的な構造を示しています。

Class EFILE.Service Extends Ens.BusinessService 
{
Parameter ADAPTER = "EnsLib.File.InboundAdapter";

Method OnProcessInput(pInput As %FileCharacterStream,pOutput As %RegisteredObject) As %Status
{
   set tsc=$$$OK
   //your code here
   Quit tsc
}
}

代わりに、予想されるファイルの内容に応じて、OnProcessInput() への最初の引数を %FileBinaryStreamOpens in a new tab にすることができます。

Note:

スタジオには、上記のようなビジネス・サービス・スタブの作成に使用できるウィザードが用意されています。このウィザードにアクセスするには、[ファイル][新規作成] をクリックし、[プロダクション] タブをクリックします。次に [ビジネス・サービス] をクリックして [OK] をクリックします。このウィザードには、汎用入力引数が用意されています。ウィザードを使用する場合は、このアダプタに必要な特定の入力引数を使用するようにメソッド・シグニチャを編集することをお勧めします。入力引数の型は %FileCharacterStreamOpens in a new tab または %FileBinaryStreamOpens in a new tab にする必要があります。

OnProcessInput() メソッドの実装

ビジネス・サービス・クラス内では、OnProcessInput() メソッドに次のシグニチャを含める必要があります。

Method OnProcessInput(pInput As %FileCharacterStream,pOutput As %RegisteredObject) As %Status

または :

Method OnProcessInput(pInput As %FileBinaryStream,pOutput As %RegisteredObject) As %Status

説明 :

  • pInput は、アダプタがこのビジネス・サービスに送信するメッセージ・オブジェクトです。これは、予想されるファイルの内容に応じて、%FileCharacterStreamOpens in a new tab%FileBinaryStreamOpens in a new tab のどちらかの型にすることができます。アダプタ設定 ([文字セット]) を使用して、入力ファイルが文字かバイナリかを指定します。"“ファイル受信アダプタに関する設定”" を参照してください。

    いずれの場合も、pInput.Attributes("Filename") はファイルの名前と一致します。

  • pOutput は、メソッド・シグニチャに必要な汎用出力引数です。

OnProcessInput() メソッドは、以下の一部またはすべてを実行する必要があります。

  1. 入力ファイル (pInput) を検査して、その使用方法を決定します。

  2. ビジネス・サービスから送信されることになる要求メッセージのインスタンスを作成します。

    メッセージ・クラスの作成方法は、"Ensemble プロダクションの開発" の “Ensemble メッセージの定義” を参照してください。

  3. 要求メッセージの場合は、必要に応じて、入力内の値を使用してそのプロパティを設定します。

  4. ビジネス・サービスの適切なメソッドを呼び出して、要求をプロダクション内の宛先に送信します。具体的には、SendRequestSync()SendRequestAsync()、または (あまり一般的ではない) SendDeferredResponse() を呼び出します。詳細は、"Ensemble プロダクションの開発" の “要求メッセージの送信” を参照してください。

    これらの各メソッドは、ステータス (具体的には、%StatusOpens in a new tab のインスタンス) を返します。

  5. 必ず出力引数 (pOutput) を設定します。通常、受信した応答メッセージと同じように設定します。この手順は必須です。

  6. 適切なステータスを返します。この手順は必須です。

アダプタ・メソッドの呼び出し

ビジネス・サービス内では、以下のアダプタのインスタンス・メソッドを呼び出すことができます。各メソッドはアダプタ設定に対応しています。これらのメソッドによって、設定の変更後に調整の機会が与えられます。各設定の詳細は、後述する “ファイル受信アダプタに関する設定” を参照してください。

ArchivePathSet()
Method ArchivePathSet(pInVal As %String) As %Status

pInVal は、アダプタがファイルの処理を完了した後に、各ファイルのコピーを格納するディレクトリです。

FilePathSet()
Method FilePathSet(path As %String) As %Status

path は、ローカル・サーバ上のファイルの検索先ディレクトリです。

WorkPathSet()
Method WorkPathSet(path As %String) As %Status

WorkPath

path は、ファイルの処理中にファイルを格納するローカル・サーバ上のディレクトリです。

ビジネス・サービス・クラスの例

例 1

EnsLib.File.InboundAdapterOpens in a new tab を参照するビジネス・サービス・クラスのコードの例を以下に示します。この例は、以下のように動作します。

  1. ファイルにはヘッダがあります。ヘッダ情報が各トランザクションに追加されます。

  2. ファイルには多数のトランザクションがあります。

  3. ヘッダとトランザクション XML 構造が、LBAPP.Header クラスと LBAPP.Transaction クラスによって定義されます (これは表示されていません)。

  4. エラー処理がいくつか表示されていますが、すべてではありません。

  5. RejectBatch() メソッドは表示されていません。

  6. トランザクションは非同期でビジネス・プロセスに送信されるため、ファイル内の順番どおりに処理されるという保証はありません。

  7. トランザクション・オブジェクト全体が各メッセージのペイロードとしてビジネス・プロセスに渡されます。

  8. 1 つのファイル内のすべてのトランザクションが、1つの Ensemble セッションで送信されます。

Class LB.MarketOfferXMLFileSvc Extends Ens.BusinessService
{
Parameter ADAPTER = "EnsLib.File.InboundAdapter";

Method OnProcessInput(pInput As %FileCharacterStream,
                      pOutput As %RegisteredObject) As %Status
{
 // pInput is a %FileCharacterStream containing the file xml

 set batch=pInput.Filename // path+name.ext
 set batch=##class(%File).GetFilename(batch) // name.ext

 // Load the data from the XML stream into the database
 set reader = ##class(%XML.Reader).%New()

 // first get the header
 set sc=reader.OpenStream(pInput)
 if 'sc {
   do $this.RejectBatch("Invalid XML Structure",sc,pInput,batch)
   quit 1
   }
 do reader.Correlate("Header","LBAPP.Header")
 if (reader.Next(.object,.sc)) {set header=object}
 else {
   if 'sc {do $this.RejectBatch("Invalid Header",sc,pInput,batch)}
   else {do $this.RejectBatch("No Header found",sc,pInput,batch)}
   quit 1
   }

 // then get the transactions, and call the BP for each one
 do reader.Correlate("Transaction","LBAPP.Transaction")
 while (reader.Next(.object,.sc)) {
   set object.Header=header
   set sc=$this.ValidateTrans(object)
   if sc {set sc=object.%Save()}
   if 'sc {
   do $this.RejectTrans("Invalid transaction",sc,object,batch,tranct)
   set sc=1
   continue
   }

 // Call the BP for each Transaction
 set request=##class(LB.TransactionReq).%New()
 set request.Tran=object
 set ..%SessionId="" // make each transaction a new session
 set sc=$this.SendRequestAsync("LB.ChurnBPL",request)
 }

 do reader.Close()
 quit sc
}
}

例 2

EnsLib.File.InboundAdapterOpens in a new tab を使用するビジネス・サービス・クラスのコードの例を以下に示します。コードのコメントは、OnProcessInput() 内のアクティビティを説明しています。

Class training.healthcare.service.SrvFilePatient Extends Ens.BusinessService
{

Parameter ADAPTER = "EnsLib.File.InboundAdapter";

Method OnProcessInput(pInput As %RegisteredObject,
                      pOutput As %RegisteredObject) As %Status
{

  //file must be formatted as set of lines, each field comma separated:
  //externalcode,
  //name, surname, dateBirth, placeBirth, provinceBirth
  //nationality, gender,
  //address, city, province, country,
  //fiscalCode
  //note:
  //fiscalCode may be optional
  //sso is an internal code so must be detected inside ensemble
  //operation must be detected as well:
  //if the group: name, surname, dateBirth, placeBirth, provinceBirth
  //point to a record then it's an UPDATE; if not it's a NEW
  //no DELETE via files

  Set $ZT="trap"

  set counter=1  //records read
  while 'pInput.AtEnd {
    set line=pInput.ReadLine()

    set req=##class(training.healthcare.message.MsgPatient).%New()
    set req.source="FILE"

    set req.externalCode=$piece(line,",",1)
    set req.name=$piece(line,",",2)
    set req.surname=$piece(line,",",3)
    set req.dateBirth=$piece(line,",",4)
    set req.placeBirth=$piece(line,",",5)
    set req.provinceBirth=$piece(line,",",6)
    set req.nationality=$piece(line,",",7)
    set req.gender=$piece(line,",",8)
    set req.address=$piece(line,",",9)
    set req.city=$piece(line,",",10)
    set req.province=$piece(line,",",11)
    set req.country=$piece(line,",",12)
    set req.fiscalCode=$piece(line,",",13)


    //call the process
    //res will be Ens.StringResponse type message
    set st=..SendRequestAsync(
           "training.healthcare.process.PrcPatient", req)
    if 'st
    $$$LOGERROR("Cannot call PrcMain Process for patient N°" _ counter)

    set counter=counter+1
  }

  $$$LOGINFO("patients loaded : " _ (counter - 1))
  Set $ZT=""
  Quit $$$OK

trap
  $$$LOGERROR("Error loading for record N°" _ counter _ " - " _ $ZERROR)
  SET $ECODE = ""
  Set $ZT=""
  Quit $$$OK
}

}

例 3

EnsLib.File.InboundAdapterOpens in a new tab を参照するビジネス・サービス・クラスのコードの例を以下に示します。

Class EnsLib.File.PassthroughService Extends Ens.BusinessService
{

Parameter ADAPTER = "EnsLib.File.InboundAdapter";

/// Configuration item(s) to which to send file stream messages
Property TargetConfigNames As %String(MAXLEN = 1000);

Parameter SETTINGS = "TargetConfigNames";

/// Wrap the input stream object in a StreamContainer message object
/// and send it. If the adapter has a value for ArchivePath, send async;
/// otherwise send synchronously to ensure that we don't return to the
/// Adapter and let it delete the file before the target Config Item is
/// finished processing it.

Method OnProcessInput(pInput As %Stream.Object,
                      pOutput As %RegisteredObject) As %Status
{
  Set tSC=$$$OK, tSource=pInput.Attributes("Filename"),
                 pInput=##class(Ens.StreamContainer).%New(pInput)
  Set tWorkArchive=(""'=..Adapter.ArchivePath)&&(..Adapter.ArchivePath=
    ..Adapter.WorkPath || (""=..Adapter.WorkPath && 
    (..Adapter.ArchivePath=..Adapter.FilePath)))
  For iTarget=1:1:$L(..TargetConfigNames, ",")
 { 
    Set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W")
    Continue:""=tOneTarget
    $$$sysTRACE("Sending input Stream ...")
    If tWorkArchive {
      Set tSC1=..SendRequestAsync(tOneTarget,pInput)
      Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
    } Else {
      #; If not archiving send Sync to avoid Adapter deleting file
      #; before Operation gets it
      Set tSC1=..SendRequestSync(tOneTarget,pInput)
      Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
    }
  }
  Quit tSC
}
}

この例では、tSource 変数を、受信ストリーム (pInput) が持つ Attributes プロパティの Filename 添え字に格納されている元のファイル名に設定します。

ビジネス・サービスの追加と構成

ビジネス・サービスを Ensemble プロダクションに追加するには、管理ポータルを使用して以下の操作を行います。

  1. Ensemble プロダクションにビジネス・サービス・クラスのインスタンスを追加します。

  2. ビジネス・サービスを構成します。設定の詳細は、“設定の参照先” を参照してください。

  3. ビジネス・サービスを有効化します。

  4. プロダクションを実行します。

FeedbackOpens in a new tab