Jeffrey Drumm · May 26, 2023 go to post

In addition to checking the logs, you can configure ^MONMGR and you'll get emailed on a failover (or any other significant Caché/IRIS event).

There's also ^%SYSMONMGR for notifications on other Caché/IRIS system-health events.

Jeffrey Drumm · May 23, 2023 go to post

I think in some cases questions are simply seeds planted for the growth of stimulating exchanges of ideas.

This is a topic I would find interesting, and I'm no newbie, nor am I an ISC employee.

If the answers to this question don't interest you, there are other questions that can use your help 😉

Jeffrey Drumm · May 22, 2023 go to post

Can you try the code I posted above, substituting appropriate paths/filenames in the calls to the LinkToFile() methods? Any file will do for the in stream, as long as file/directory permissions permit. This at least would tell us whether the issue is with the key file or the JWT you're attempting to encrypt.

I've tried this on I4H 2023.1 and Health Connect 2021.1.2 and the RSASHASign() method has not failed to generate a signature unless the key was passphrase-protected or not readable (due to file ownership/permissions) by the process opening it.

Jeffrey Drumm · May 22, 2023 go to post

Password-protecting the key won't prevent it from being read.

Do you have access to openssl? If yes, try the following:

openssl rsa -in <keyfile-name> -check -noout

You should get "RSA key ok" if it's a good key and has no passphrase.

Jeffrey Drumm · May 22, 2023 go to post

Is your key file passphrase-protected?

I get the output you describe when the key is passphrase-protected and the passphrase is not supplied.

Jeffrey Drumm · May 22, 2023 go to post

I just tried RSASHASign() myself and a signature was returned, using your call:
 

Set in=##class(%Stream.FileCharacter).%New()
Do in.LinkToFile("/home/jeff/sample.jwt")
Set token=in.Read()
Set key=##class(%Stream.FileCharacter).%New()
Do key.LinkToFile("/home/jeff/sample.pem")
Set secret=key.Read()
Set sig=##class(%SYSTEM.Encryption).RSASHASign(512,token,secret)

The return value will be the signature only, though, not a signed JWT. If you want the latter, see the ObjectToJWT() method in  %OAuth2.JWT - InterSystems IRIS for Health 2021.1.

Jeffrey Drumm · May 22, 2023 go to post

I believe your argument list is incorrect.

The first argument should be a string containing the data to be signed. The second is the private key, also in the form of a string. If the key is passphrase-protected, the third argument should be a string containing the passphrase.

SHA-1 is deprecated, by the way.

Jeffrey Drumm · May 20, 2023 go to post

The reason this 2-year-old thread floated to the top is because I found it researching an issue I had encountered with EnsLib.HTTP.GenericService.. I wanted to "pass through" a status code I had set as a property of a response message in a business process. While a solution was buried in the thread, the OP claimed it did not work in his case. I'm not sure why; I used a slight variation of that solution with success and simply felt the variation was worth sharing.

Jeffrey Drumm · May 20, 2023 go to post

Just in case someone stumbles into this thread looking for an answer (as I did) ...

Assuming the vanilla, un-extended EnsLib.HTTP.GenericService is the service handling the request, any response it receives from a business process needs to be an EnsLib.HTTP.GenericMessage. %Net.HttpResponse is not needed, nor is a CSP layer required.

The service requires that a stream is attached to the message; the stream doesn't need to contain anything.

The response message is composed in the BP something like this:

Set rstream = ##class(%Stream.GlobalCharacter).%New()
// Optional body content
Do rstream.Write("<HTML><HEAD>Uh oh.</HEAD><BODY><BR><STRONG>Error: Invalid Patient ID</STRONG></BODY></HTML>")
// Provide a stream object, empty is fine
Set response = ##class(EnsLib.HTTP.GenericMessage).%New(rstream)
// This works as expected in I4H 2023.1
Do response.HTTPHeaders.SetAt("HTTP/1.1 400 Bad Request","StatusLine")
// if you're providing a payload ...
Do response.HTTPHeaders.SetAt("text/html; charset=utf-8","Content-Type")

I've verified that it works as coded above, using curl:

< HTTP/1.1 400 Bad Request
< Content-Type: text/html; charset=utf-8
< Content-Length: 99
<
* Connection #0 to host iristest.local left intact
<HTML><HEAD>Uh oh.</HEAD><BODY><BR><STRONG>Error: Invalid Patient ID</STRONG></BODY></HTML>
Jeffrey Drumm · May 18, 2023 go to post

If the individual segment transformations are common across all ADT DTLs, you could implement your DTLs with subtransforms (these work at the segment level). As long as the gross structure of the messages rarely changes, the maintenance is all done in segment DTLs.

Jeffrey Drumm · May 17, 2023 go to post

With #2 (at least for me anyway), the issue seems to be related to running iris session when using the Windows version of ssh.exe (called from VS Code, configured in settings under node terminal.integrated.profiles.windows). Home and End work normally at the Linux shell prompt, but when running iris session the effect is that either key produces the same result as pressing the Enter key. The current command is executed and a new IRIS prompt is generated.

It doesn't seem to be a VS Code problem so much as an ISC problem, at least on Windows.

Jeffrey Drumm · May 17, 2023 go to post

This should work (no looping required):

I'm using the parenthesis syntax with the Matches() function to locate a pattern of any number of punctuation characters (.P) followed by 8 numeric characters (8N) followed by any number of any character (.E).

The parenthesis syntax returns the repeating values in the form "<><><20230512191543><>" where <> represents an empty iteration of the repeating field (and fortunately qualifies as a punctuation character).

Jeffrey Drumm · May 16, 2023 go to post

According to a StackOverflow thread I just read, the connection url below is purported to work on Linux and authenticate with the MS JDBC driver:

jdbc:sqlserver://[server]:[port];database=[db];trustServerCertificate=true;integratedSecurity=true;user=[user without domain];password=[pw];authenticationScheme=NTLM;domain=[domain];authentication=NotSpecified
Jeffrey Drumm · May 5, 2023 go to post

Ok, answering my own question ...

Ens.MonitorService calls the macro $$$SetHostMonitor() when the InactivityTimeout is reached, which does this:

Set $$$EnsHostMonitorRoot($namespace,%host,%prop)=%val,$$$EnsHostMonitorRoot($namespace,%host,$$$eMonitorLastActivity)=$$$timeUTC

And that certainly appears to be updating the LastActivity time.

Jeffrey Drumm · May 3, 2023 go to post

ISCAgent is running on primary, alternate and arbiter? It has to be running on all 3. IRIS Windows installation by default will install ISCAgent but will not enable it for auto-start.

Jeffrey Drumm · May 2, 2023 go to post

If you set the ENSLIB database to mount read/write, it will compile. I'm wondering if, after recompilation, it will work ...

Jeffrey Drumm · May 1, 2023 go to post

I couldn't even get that class to compile until I set the ENSLIB database to mount R/W. And yes, I was attempting to compile it in a conventional "interoperability-enabled" namespace. That's on I4H 2022.2, fyi.

Does it compile without error on your system?

Jeffrey Drumm · Apr 27, 2023 go to post

Web services normally use an HTTP status code; for example, an ACK would be 200 OK for REST/HTTP and would be available through the %Net.HttpResponse Object in the StatusCode/StatusLine properties. SOAP usually provides some sort of payload along with the status code, and that would be found in the Data property. The type of response would likely be identified in the source/target system's WSDL for the SOAP interface.

Jeffrey Drumm · Apr 26, 2023 go to post

This is something I wrote a long time ago; it extracts all business hosts and their settings. I've learned some things since I wrote it and would probably do a few things differently these days. It should be enough to give you some ideas, though ...

ClassMethod GetConfigs(pProduction As %String = {$G(^Ens.Runtime("Name"),$G(^Ens.Suspended,$G(^Ens.Configuration("csp","LastProduction"))))}, pFile As %String = {$System.Util.GetEnviron("HOME")_"/"_$NAMESPACE_"_hostconfigs.csv"}) As %Status
{
    Set tPrd = ##class(Ens.Config.Production).%OpenId(pProduction)
    Set tOut = ##class(%File).%New()
    Set tOut.Name = pFile
    Set tSC = tOut.Open("RWN")
    if '$$$ISERR(tSC)
    {
        Set tSC = vOut.WriteLine("""Type"",""Name"",""ClassName"",""Adapter"",""Enabled"",""ConfigName"",""ConfigValue""")
    }
    Quit:$$$ISERR(tSC) tSC
    If $ISOBJECT(tPrd)
    {
        For i=1:1:tPrd.Items.Count()
        {
            Set tHost = tPrd.Items.GetAt(i)
            Set tName = tHost.Name
            Set tClassName = tHost.ClassName
            Set tType = $CASE(tHost.BusinessType(),0:"Unknown",1:"Service",2:"Process",3:"Operation",4:"Actor",:"Huh?")
            Set tAdapter = $CLASSMETHOD(tClassName,"%GetParameter","ADAPTER")
            Set tEnabled = tHost.Enabled
            Set tCategory = tHost.Category
            Set tLine = """"_tType_""","""_tName_""","""_tClassName_""","""_tAdapter_""","""_tEnabled_""","""
            Do tOut.WriteLine(tLine_"Category"","""_tCategory_"""")
            For l=1:1:tHost.Settings.Count()
            {
                Set tCfg = tHost.Settings.GetAt(l)
                Set tCfgName = tCfg.Name
                Set tCfgVal = tCfg.Value
                Set tSC = vOut.WriteLine(tLine_tCfgName_""","""_tCfgVal_"""")
                Return:$$$ISERR(tSC) tSC
            }
        }
        Do tOut.Close()
    }
    Else
    {
        Return $$$ERROR(0,"Production Not Found in this namespace")
    }
    Return $$$OK
}
Jeffrey Drumm · Apr 26, 2023 go to post

The error in your previous post seems to indicate that no filename was available for creating or appending. The path shown in the error does not include a filename.

Jeffrey Drumm · Apr 24, 2023 go to post

If the outbound operation is configured to use %f as the filename and has the Overwrite checkbox unchecked, the output file will have the same name and all records from the input file.

You mostly likely will have the input service and output operation set for different directories. Relying on the source file name may prove to be problematic if the inbound file has the same name every time it's received.

Jeffrey Drumm · Apr 24, 2023 go to post

I assumed there would be a way to accomplish this with a form of OS/Delegated authentication, but I may be wrong. It wouldn't be the first time wink

EDIT:​​​​​ Let me amend that. OS authentication works only for users whose OS accounts exist in IRIS, right? So don't create any IRIS users that have matching OS accounts ... With the exception of the account that needs OS authentication.

Jeffrey Drumm · Apr 23, 2023 go to post

@Padmaja Konduru's solution works from the IRIS/Caché prompt when in the proper namespace.

If you need to be able to script this from the OS, there will be additional steps required, such as piping command input to iris session <instance> from the OS shell. You will likely need to include a username and password in the piped input, which is generally not a good idea. Enabling OS authentication may be an option, but that's a global setting and not (easily) configurable per-user.

Jeffrey Drumm · Apr 20, 2023 go to post

While $$$FormatText() is a great tool, I'd give my left ... uh, leg to have a sprintf() workalike that handles left/right justification, padding, number precision formatting, date element tokens, etc.

I guess we'll just have to make do with Python f-strings ... wink

Jeffrey Drumm · Apr 20, 2023 go to post

Theoretically, yes. HCC supports ODBC access as of August 2022, but I suspect updates to firewall rules on your VPN connection to your HCC instances will be required. I believe TLS will have to be enabled for the ODBC connection as well (HL7 Spy can support this).

You'll also need to install the server-side class to support the fetching of HL7 messages (HICG_HL7.xml) to any interoperability namespace that you'll need access to from HL7 Spy.

The HCC instances are pretty locked-down, so user role(s) may have to be adjusted for access to the required tables ... and that may require special dispensation from ISC.

Jeffrey Drumm · Apr 20, 2023 go to post

EDIT: Hah, I guess you posted your solution as I was typing this ... and yeah, sort of what I thought it might be laugh

Are you calling (and testing) this from a DTL? If yes, have you looked through the DTL rules to see if the returned string's variable is being used as an argument to something like $system.Status.GetErrorText()?

Does the same thing happen when you execute it from the IRIS prompt?

Set tStrm=##class(%Stream.GlobalBinary).%New()
Do tStrm.Write("SGVsbG8gV29ybGQh")
Do tStrm.Rewind()
Write ##class(<packagename>).DecodeBase64HL7ToFile(tStrm,"<ancillary>","</path/to/outputfile.ext>")

Replace <packagename>, <ancillary>, and </path/to/outputfile.ext> with values appropriate for what you're testing, of course ...

Jeffrey Drumm · Apr 19, 2023 go to post

ImageMagick is likely available for your platform and can be called using $ZF(-100). It has a LOT of image conversion options.

A sample command line for svg to png conversion:

$ convert -background none -density 1000 -resize 1000x myvector.svg myraster.png

Example using $ZF(-100):

Class User.Util.Image [ Abstract ]
{

ClassMethod Convert(pSourceFile As %String, pDestFile As %String, pDensity As %Integer = 1000, pResize As %String = "1000x", pBackground As %String = "none") As %Status
{
    Set OsCmd = "/usr/bin/convert"
    Set OsArgs(1) = "-background"
    Set OsArgs(2) = pBackground  // "none" for transparent and black for formats w/o alpha channel
    Set OsArgs(3) = "-density"
    Set OsArgs(4) = pDensity // set the vector width before resizing for best image quality
    Set OsArgs(5) = "-resize"
    Set OsArgs(6) = pResize // image output width/height (default is width 1000 keeping aspect ratio)
    Set OsArgs(7) = pSourceFile
    Set OsArgs(8) = pDestFile // file type controlled by extension; .png, .jpg, .gif etc.
    Set OsArgs = 8
    Set tRC = $ZF(-100,"",OsCmd,.OsArgs)
    // On Linux, a return code of 0 indicates success
    If '(tRC = 0)
    {
        Return $$$ERROR(5001,"OsCmd "_OsCmd_" Returned Error Code ["_tRC_"]")
    }
    Return $$$OK
}

}

Called like this:

Set tSC = ##class(User.Util.Image).Convert("/path/to/filename.svg", "/path/to/filename.png")
Jeffrey Drumm · Apr 18, 2023 go to post

Well, I learned something new too! I've always created classes in the Explorer pane and never realized that the Interoperability class types were templated out as file types. As someone who works primarily with Health Connect/IRIS for Health/HealthShare, that's pretty cool!