Marc Mundt · Jun 14, 2022 go to post

For the outbound REST calls, I would typically create a custom operation class that calls methods in %SYS.OAuth2.* to fetch a token from the downstream system and then places that in the HTTP header.

If it's essential for you to avoid creating a custom class, you could call the %SYS.OAuth2 methods from a BPL and then add the token to the header fields in the EnsLib.HTTP.GenericMessage that you send to the GenericOperation.

You haven't said what needs to happen between the business service and business operation, so it's hard to discuss how everything fits together as you asked.

Marc Mundt · Jun 13, 2022 go to post

Yes, the GenericService will send an EnsLib.HTTP.GenericMessage object to your business process. The GenericMessage includes the headers and content of the inbound HTTP request. Your DTL can use these fields to transform to another format.

Similarly, the GenericOperation accepts the same GenericMessage type and uses the values in it to issue an HTTP request to the downstream system.

So all together, this allows you to create a REST web service and/or call out to external REST services using only the GUI.

https://docs.intersystems.com/irisforhealth20221/csp/docbook/DocBook.UI…

Marc Mundt · Jun 6, 2022 go to post

Here's a sample class to Base64 encode a stream:

Class Example.B64.Util Extends %RegisteredObject
{

/// Be cautious if changing CHUNKSIZE. Incorrect values could cause the resulting encoded data to be invalid.
/// It should always be a multiple of 57 and needs to be less than ~2.4MB when MAXSTRING is 3641144
Parameter CHUNKSIZE = 2097144;

ClassMethod B64EncodeStream(pStream As %Stream.Object, pAddCRLF As %Boolean = 0) As %Stream.Object
{
    set tEncodedStream=##class(%Stream.GlobalCharacter).%New()
    
    do pStream.Rewind()
    
    while ('pStream.AtEnd) {
        set tReadLen=..#CHUNKSIZE
        set tChunk=pStream.Read(.tReadLen)
        
        do tEncodedStream.Write($System.Encryption.Base64Encode(tChunk,'pAddCRLF))
        if (pAddCRLF && 'pStream.AtEnd) {
            do tEncodedStream.Write($c(13,10))
        }
    }
    
    do tEncodedStream.Rewind()
    
    quit tEncodedStream
}
}
Marc Mundt · May 24, 2022 go to post

Fortunately it's a simple issue. In your CALL action, you need to add a "Request Action" and set callrequest to the object you want to send to the BO. It looks like you're just modifying the inbound request so you could just set callrequest to request.

Marc Mundt · May 20, 2022 go to post

If you can assume that the zip is always 5 digits and state is 2 digits, and if you can assume that the separator is always 1 character then you can do it by position:

set ZIP=$EXTRACT(x,*-4,*), STA=$EXTRACT(x,*-7,*-6), CTY=$EXTRACT(x,0,*-9)
Marc Mundt · May 5, 2022 go to post

Try removing the JsonArayOBJ argument from your call to SendFormDataURL.

set st = ..Adapter.SendFormDataURL(..Adapter.URL,.callResponsePat,"POST",HTTPRequestPat)
Marc Mundt · May 5, 2022 go to post

Can you give some more details on what's happening? Is there an error message?

Marc Mundt · May 5, 2022 go to post

Can you clarify a bit?

Do you want to use curl to make an HTTP request to a web service running in Ensemble? Or do you want Ensemble to launch curl to make an HTTP request to an external web service?

Marc Mundt · Apr 29, 2022 go to post

You can put something similar to Jeffrey's logic directly in the Value of the Set action. Instead of using $E ($EXTRACT) you would use DTL's built-in SubString function:

..SubString("123456789",1,3)_"-"_..SubString("123456789",4,5)_"-"_..SubString("123456789",6,9)
Marc Mundt · Apr 26, 2022 go to post

Is there already a defined structure for these globals/do these globals already exist? Or will you design something new?

Marc Mundt · Apr 26, 2022 go to post

Can you explain more about your use case? What is the purpose of copying these fields directly into globals? Is there another application that will read the values from the globals?

Marc Mundt · Apr 25, 2022 go to post

All persistent classes will save their data in globals automatically. It will save using the standard structures of the IRIS SQL layer.

If you have an existing global structure that you need to maintain you'll need to map your classes to your global structure. See this series of articles on how to do that.

Marc Mundt · Apr 22, 2022 go to post

I messed up the syntax:

&sql(select LIST(MessageName), LIST(Identifier) INTO :tMsgNmList, :tIdentList from GMECC_DocmanConnect_Tables.ParisConnecMessagetSettings)
Marc Mundt · Apr 22, 2022 go to post

How about this? Do the values returned in tMsgNmList and tIdentList match the values you're searching for?

&sql(select LIST(MessageName) INTO :tMsgNmList, LIST(Identifier) INTO :tIdentList from GMECC_DocmanConnect_Tables.ParisConnecMessagetSettings)

write SQLCODE, ":", tMsgNmList,":",tIdentList,!
Marc Mundt · Apr 21, 2022 go to post

If you try this what does it return?

&sql(select count(*) INTO :tCount from GMECC_DocmanConnect_Tables.ParisConnecMessagetSettings Where  MessageName = :tMessageName and Identifier = :tIdentifier)

write SQLCODE, ":", tCount,!
Marc Mundt · Apr 13, 2022 go to post

And does your target message really need to be an ADT_A01? Merges use ADT_A18 messages, so you can just set ADT_A18 as your target message type and it will allow you to add the MRG segment:

Marc Mundt · Apr 13, 2022 go to post

Just to add a bit of context to the above:
An example use case where you would want to return the operation's response back to the service would be in an HL7 integration where, instead of having the service generate an ACK to return to the upstream sending system, we want to return the ACK or NAK that we got back from the downstream receiving system.

Marc Mundt · Apr 13, 2022 go to post

What Response From does is control which responses from a call to an operation (or another component) are returned to the business service that called the router. By default the router won't return the response to the service, but setting Response From will enable responses to be returned from specific operations (or * for all operations). This is how you can control which response gets sent back to the service in a case when a router calls multiple operations. If multiple responses match the Response From setting, then only the first response will be returned to the service.

Response Target Config Names allows you to specify additional components (beyond the service that called the router) that should receive a copy of the response that came back from the operation. So you could send a copy of an ACK or other response to another operation for some reason.

All of this is probably moot, because I'm guessing your service doesn't need to receive a response.

In terms of the NULL responses, these shouldn't become orphans -- the fact that they appear in the message trace tells us that the production knows which session they belong to so they should get deleted along with the rest of the session.

Marc Mundt · Apr 12, 2022 go to post

Absolutely. You can do this with two assign actions:

First assign action moves the stream pointer to the end of the stream content:

The second assign action writes our new content to the end of the stream:

And an extra note of explanation: what we're actually doing with these assigns is calling a method in the request class, which returns a status code, and assigning that status code to a temporary variable. It would be best to check this status code to see if there was an error, but I haven't added that here to keep things simple.

Marc Mundt · Apr 11, 2022 go to post

The PassthroughService will place the file contents in a stream, insert that stream into an Ens.StreamContainer object and send that to the Business Process. So Ens.StreamContainer, and the stream that it contains, is what your Business Process code will need to work with.

See this page for information on working with streams. Streams are different than simple strings and require using stream-specific methods for reading and writing content into the stream.

Unless you have a specific reason to write your business process in ObjectScript, I would recommend that you create a BPL-based business process using the visual BPL editor. There are more details here on creating business processes.

Marc Mundt · Apr 11, 2022 go to post

A few questions that will help us to understand better:
- Which business service are you using? Is it custom or out-of-the-box?
- If the service is custom, what type of object is it sending to the Business Process?
- What type of Business Process are you using? Is it BPL, ObjectScript, or a router using routing rules?

Marc Mundt · Apr 5, 2022 go to post

This section in the docs discusses business processes and routers. You could use either one -- routing rules tend to be faster/easier to create.

Basically, your business process or routing rule would create a notification message and send it to a business operation. The process/router could construct the notification message directly or could call a data transformation that would create the notification message.

The operation would send the notification to an external system. One example would be to use an email operation to send the notification to an email server.

Our online learning portal also has some courses that cover these topics:

Integration Architecture
https://learning.intersystems.com/course/view.php?id=908

Building a Message Router
https://learning.intersystems.com/enrol/index.php?id=1745

Building BPL Business Processes
https://learning.intersystems.com/enrol/index.php?id=1290

Data Transformations Basics
https://learning.intersystems.com/course/view.php?id=1170

Marc Mundt · Apr 5, 2022 go to post

Can you elaborate on the limitations you see in DocumentType that are leading you to think about using Custom Pairs?

DocumentType is of type HS.SDA3.CodeTableDetail.DocumentType, which can store a code, description, and the code system. Seems like that's what you need, and it already maps to DocumentReference:type in FHIR.

Marc Mundt · Apr 5, 2022 go to post

After the service reads the file it will send a message containing the file contents to whatever Business Process you've set as it's target. Your business process or router could send a notification message wherever needed.