· Jun 25, 2019

Cache Ensemble


Working on to learn very basic CUSTOM Business Service which sends to a  EnsLib.File.PassthroughOperation.

But operation is not writing to File and erroring out (No Stream contained in StreamContainer Request")'.

How do convert the object to STREAM and wrap in the StreamContainer so the operation does not error and write to a file.


Persistent Class

Class Hospital.PatientApptRequest Extends %Persistent
Property PatientId As %Stream.FileCharacter;
Property PatientName As %Stream.FileCharacter;


Custom Service reads from a file

Method OnProcessInput(pInput As %FileCharacterStream, Output pOutput As %RegisteredObject) As %Status
set tSC = $$$OK
    set pInput.LineTerminator=$c(10)
while 'pInput.AtEnd {
          set tMsg = ##class(Hospital.PatientApptRequest).%New()
          set tLine = pInput.ReadLine()
          set tMsg.PatientId = tLine
          set tLine = pInput.ReadLine()
          set tMsg.PatientName = tLine
          do pInput.ReadLine()
          set tRequest1=##class(Ens.StreamContainer).%New(tMsg)
          set tSC = ..SendRequestAsync(..TargetConfigNames,tRequest1)
} }
catch ex 
set tSC = ex.AsStatus()
quit tSC

Sample File contents







Jimmy Christian.

Discussion (8)1
Log in or sign up to continue

Hi Jimmy,

The problem - I think - is that you are passing an object of class Hospital.PatientApptRequest (which is not a stream) into an Ens.StreamContainer. What should work is

set tRequest1=##class(Ens.StreamContainer).%New(pInput)

Of course this makes the tMsg object redundant, but maybe you have another purpose for that elsewhere in your code.

As an aside, it is a good habit to have your class Hospital.PatientApptRequest inherit from Ens.Request instead of %Persistent. This is relevant when you want to purge old message traces.

Have fun developing your integration skills!

Thank you Aldo for checking this out. I tried to make it much simpler by using what you suggested. I was hoping the operation to  accept it since pInput is a Stream.

But still the same error. Operation does not find STREAM in the ENS. StreamContainer.

Class Hospital.ApptListFileService Extends Ens.BusinessService
Parameter ADAPTER = "EnsLib.File.InboundAdapter";
Parameter SETTINGS = "TargetConfigNames";
Property TargetConfigNames As Ens.DataType.ConfigName;
Property SentMsg As %FileCharacterStream;

Method OnProcessInput(pInput As %FileCharacterStream, Output pOutput As %RegisteredObject) As %Status
set tSC = $$$OK
    set pInput.LineTerminator=$c(10)
while 'pInput.AtEnd {
          do pInput.ReadLine()
          set tRequest=##class(Ens.StreamContainer).%New(pInput)
          set tSC = ..SendRequestAsync(..TargetConfigNames,tRequest)

Ens.StreamContainer's %New() method expects a string as the first parameter rather than a stream object.

Something like this should work:

set tRequest=##class(Ens.StreamContainer).%New()
set tSC=tRequest.StreamSet(pInput)

Or if you're trying to send one Ens.StreamContainer for each line from the input file you could do this:

while 'pInput.AtEnd {
    set tReadLength=32000
    set tLine=pInput.ReadLine(.tReadLength,.tSC)
    set tRequest=##class(Ens.StreamContainer).%New(tLine)
    //... do other stuff

One other thing you should be aware of. The following will not work if TargetConfigNames has more than one target selected:

set tSC = ..SendRequestAsync(..TargetConfigNames,tRequest)

You should add a loop using $LENGTH and $PIECE and do a SendRequestAsync for each item in TargetConfigNames' comma-separated string.

Are you sure about:

Property PatientId As %Stream.FileCharacter;
Property PatientName As %Stream.FileCharacter;

Both of these fields are less than 3 641 144 characters in size, so

Property PatientId As %VarString;
Property PatientName As %VarString;

Would probably work.

You can add ToStream() method to your class to provide serialization, if you need to (Or just add JSON or XML adaptors to generate XML or JSON (de)serializations automatically).