Skip to main content

Using the File Inbound Adapter

This topic describes how to use the file inbound adapter (EnsLib.File.InboundAdapterOpens in a new tab).

Tip:

InterSystems IRIS® data platform also provides specialized business service classes that use this adapter, and one of those might be suitable for your needs. If so, no programming would be needed. See Connectivity Options.

Overall Behavior

EnsLib.File.InboundAdapterOpens in a new tab finds a file in the configured location, reads the input, and sends the input as a stream to the associated business service. The business service, which you create and configure, uses this stream and communicates with the rest of the production. If the inbound file adapter finds multiple files in the configured location, it processes them in order of the time, earliest first, based on when the file was last modified. But the adapter ignores any fractional seconds in the time value. Consequently, if two or more files have a modified date-time differing only in the fractional second part of the time, the adapter can process them in any order.

The following figure shows the overall flow:

File flowing from outside a production through a file inbound adapter and business service

In more detail:

  1. Each time the adapter encounters input from its configured data source, it calls the internal ProcessInput() method of the business service class, passing the stream as an input argument.

  2. The internal ProcessInput() method of the business service class executes. This method performs basic production tasks such as maintaining internal information as needed by all business services. You do not customize or override this method, which your business service class inherits.

  3. The ProcessInput() method then calls your custom OnProcessInput() method, passing the stream object as input. The requirements for this method are described in Implementing the OnProcessInput() Method.

The response message follows the same path, in reverse.

Creating a Business Service to Use the Inbound Adapter

To use this adapter in your production, create a new business service class as described here. Later, add it to your production and configure it. You must also create appropriate message classes, if none yet exist. See Defining Messages.

The following list describes the basic requirements of the business service class:

The following example shows the general structure that you need:

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
}
}

The first argument to OnProcessInput() could instead be %FileBinaryStreamOpens in a new tab, depending on the contents of the expected file.

Implementing the OnProcessInput() Method

Within your business service class, your OnProcessInput() method should have the following signature:

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

Or:

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

Where:

The OnProcessInput() method should do some or all of the following:

  1. Examine the input file (pInput) and decide how to use it.

  2. Create an instance of the request message, which will be the message that your business service sends.

    For information on creating message classes, see Defining Messages.

  3. For the request message, set its properties as appropriate, using values in the input.

  4. Call a suitable method of the business service to send the request to some destination within the production. Specifically, call SendRequestSync(), SendRequestAsync(), or (less common) SendDeferredResponse(). For details, see Sending Request Messages.

    Each of these methods returns a status (specifically, an instance of %StatusOpens in a new tab).

  5. Make sure that you set the output argument (pOutput). Typically you set this equal to the response message that you have received. This step is required.

  6. Return an appropriate status. This step is required.

Invoking Adapter Methods

Within your business service, you might want to invoke the following instance methods of the adapter. Each method corresponds to an adapter setting; these methods provide the opportunity to make adjustments following a change in any setting. For detailed descriptions of each setting, see Settings for the File Inbound Adapter.

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

pInVal is the directory where the adapter should place a copy of each file after processing.

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

path is the directory on the local server in which to look for files.

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

WorkPath

path is the directory on the local server in which to place files while they are being processed.

Understanding the Adapter Archiving Behavior

After the business service sends a request to some destination within the production, the adapter may archive or delete the input file that triggered the request. The following table describes the archiving behavior of the adapter given various settings.

You can use the table to choose the combination of settings that best suits your environment. For example, if the production uses a Message Bank operation to track message bodies from the business service, you can use the first scenario to ensure that the contents of files are archived to the Message Bank before the file streams are removed. For more information, see Configuring the Enterprise Message Bank. You can use the third and fourth scenarios to permanently retain archived input files. You can use the sixth scenario to trigger an event on the target host that is independent of the contents of the input file since the file may be deleted, causing a potential race condition.

In all the scenarios except the third and fourth scenarios, InterSystems IRIS purges the input file during a manual or scheduled purge if the Include message bodies setting is set to true.

Note:

The adapter can rename or delete a file sent to host only if the method does not return an error.

Scenario ArchivePath and WorkPath Request Type File Sent to Host File Location
1 ArchivePath and WorkPath are the same, but different from FilePath Async Input file renamed ArchivePath + filename (with optional timestamp) ArchivePath + filename (with optional timestamp)
2 ArchivePath and WorkPath are not set Sync Input file

If Delete From Server is true, none

If Delete From Server is false, input directory

Note:

You can set Delete From Server to false only by customizing the business service. For instructions, see Adding and Removing Settings.

3 ArchivePath is different from FilePath, and WorkPath is not set Sync Input file ArchivePath + filename (with optional timestamp)
4 ArchivePath is different from WorkPath, which is different from FilePath Sync Input file renamed WorkPath + filename (with optional timestamp) ArchivePath + filename (with optional timestamp)
5 ArchivePath is not set, and WorkPath is different from FilePath Sync Input file renamed WorkPath + filename (with optional timestamp)

If Delete From Server is true, none

If Delete From Server is false, WorkPath + filename (with optional timestamp)

6 ArchivePath is the same as FilePath, and WorkPath is not set Async Input file

If Delete From Server is true, none

If Delete From Server is false, input directory

Example Business Service Classes

Example 1

The following code example shows a business service class that references the EnsLib.File.InboundAdapterOpens in a new tab. This example works as follows:

  1. The file has a header. The header information is added to each transaction.

  2. The file experiences a number of transactions.

  3. The header and transaction XML structures are defined by the classes LBAPP.Header and LBAPP.Transaction (not shown).

  4. Some error-handling is shown, but not all.

  5. The method RejectBatch() is not shown.

  6. The transactions are submitted to the business process asynchronously, so there is no guarantee they are processed in order as they appear in the file.

  7. The entire transaction object is passed as the payload of each message to the business process.

  8. All of the transactions in one file are submitted as a single InterSystems IRIS session.

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
}
}

Example 2

The following code example shows another business service class that uses the EnsLib.File.InboundAdapterOpens in a new tab. Code comments explain the activities within OnProcessInput():

Class training.healthcare.service.SrvFilePerson 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 InterSystems IRIS Interoperability
  //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.MsgPerson).%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.PrcPerson", req)
    if 'st
    $$$LOGERROR("Cannot call PrcMain Process for Person N°" _ counter)

    set counter=counter+1
  }

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

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

}

Example 3

The following code example shows a business service class that references the 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 you move the input file to the ArchivePath or delete the file 
/// after sending, send the message object synchronously. Doing so prevents 
/// a race condition, that is, a situation where the adapter attempts to 
/// delete or modify the file while the target Config Item is still processing it.
/// Alternatively, send the object asynchronously.
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 {
      Set tSC1=..SendRequestSync(tOneTarget,pInput)
      Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1)
    }
  }
  Quit tSC
}
}

This example sets the tSource variable to the original file name which is stored in the Filename subscript of the Attributes property of the incoming stream (pInput).

InterSystems recommends sending an asynchronous request only if you do not intend to move or delete the input file. For additional guidance, see Understanding the Adapter Archiving Behavior.

Adding and Configuring the Business Service

To add your business service to a production, use the Management Portal to do the following:

  1. Add an instance of your business service class to the production.

  2. Configure the business service. For information on the settings, see Reference for Settings.

  3. Enable the business service.

  4. Run the production.

FeedbackOpens in a new tab