go to post Jeffrey Drumm · Mar 31, 2023 Well I guess there IS a setting (thanks, @Eduard Lebedyuk!) The parameter Undefined specifies the behavior when ObjectScript attempts to fetch the value of a variable that has not been defined. The value of Undefined may be 0, 1, or 2: 0 - Always throw an <UNDEFINED> error. (default) 1 - If the undefined variable has subscripts, return a null string, but if the undefined variable is single-valued, throw an <UNDEFINED> error. 2 - Always return a null string. You can change that setting in System Administration | System Configuration | Additional Settings | Compatibility.
go to post Jeffrey Drumm · Mar 30, 2023 Not sure what version of Caché or IRIS you're on; for future reference it's helpful to include that information. In IRIS 2021.2, you can do this from the IRIS SQL Shell: JEFF>do $system.SQL.Shell() SQL Command Line Shell ---------------------------------------------------- The command prefix is currently set to: <<nothing>>. Enter <command>, 'q' to quit, '?' for help. [SQL]JEFF>>set displaypath /home/jeff/tmp/ displaypath = /home/jeff/tmp/ [SQL]JEFF>>set displayfile sqlout displayfile = sqlout [SQL]JEFF>>set displaymode csv displaymode = csv [SQL]JEFF>>set selectmode display selectmode = display [SQL]JEFF>>select top 100 * from Ens_Util.Log 13. select top 100 * from Ens_Util.Log /home/jeff/tmp/sqlout.csv /home/jeff/tmp/sqloutMessages.txt statement prepare time(s)/globals/cmds/disk: 0.0002s/6/831/0ms execute time(s)/globals/cmds/disk: 0.0035s/467/20822/0ms cached query class: %sqlcq.JEFF.cls115 --------------------------------------------------------------------------- The default delimiter is comma, but you can change that. For example, the tab character: [SQL]JEFF>>set displaydelimiter = $C(9)
go to post Jeffrey Drumm · Mar 30, 2023 A Business Process Component is the BPL analogue of a subroutine or function and is called exclusively from a BPL. The idea is that they can be reusable components applicable to potentially multiple, different business processes. I don't think that's really what you're looking for. If you don't have a FIFO concern with this database processing and are thinking that increasing the number of parallel processes performing these database activities might improve performance, you could try increasing the pool size for the BP.
go to post Jeffrey Drumm · Mar 27, 2023 There are methods for dealing with what are essentially embedded streams in HL7 Objects. See the methods GetFieldStreamRaw() and StoreFieldStreamRaw() in class EnsLib.HL7.Message; these are useful for copying streams from one message to another. If the need is to extract the Base64 stream as a binary stream for writing to a file, there's also GetFieldStreamBase64() in the same class; the stream obtained from it can be used with file-based streams to write to a disk file.
go to post Jeffrey Drumm · Mar 22, 2023 I'm not sure whether this will work in Ensemble 2018.1, but it does seem to work fine in IRIS for Health Interoperability 2022.2. I'm testing with a simple JSON file that looks like this: { "mrn": 12345678, "name": "Johann Smythe", "firstname": "Johann", "lastname": "Smythe", "dob": "1989-03-21 14:20:00", "phone": "(555) 555-4917", "mobile": "(555) 555-6401", "email": "johann@smythe.com", "address": "123 Anystreet St", "city": "Anytown", "state": "ME", "zip": "04121" } I've used the File Passthrough Service (EnsLib.File.PassthroughService) to read the JSON document into a stream, message class Ens.StreamContainer. Because this isn't an HL7 object, my router is based on the "General Message Routing Rule" rule type, and my constraint consists of the source service name with a message class of Ens.StreamContainer. In the DTL called by the send action, I use Ens.StreamContainer as the source message type. The target message type is EnsLib.HL7.Message with whatever Document Category and Type is needed. The first rule in the DTL is this: After setting a number of default values for the target HL7 message (Event Type/Trigger, Date/Time of message, etc.) I populate the PID fields as follows: And I now have an HL7 message created from JSON. This isn't going to work with a batch of patient records in a JSON array; you'd need to create a BPL to process that. But for input that consists of a simple structure like the example I used, you can accomplish what you need without building a custom service or creating a BPL.
go to post Jeffrey Drumm · Mar 21, 2023 Are you using LDAP for authentication? I seem to remember running into this when the web applications created as part of enabling Ensemble/Interoperability weren't set to support LDAP. Compare the settings for the web applications created for your new namespace in Security | Applications | Web Applications with those from other (working) Ensemble-enabled namespaces.
go to post Jeffrey Drumm · Mar 18, 2023 For those that use Interoperability/HealthConnect, nc/netcat is also an excellent tool for verifying that remote ports are accessible for HL7 MLLP, HTTP or other protocols that require a TCP socket client connection. And while this thread is specifically for Unix/Linux, there's a Windows PowerShell analogue named Test-NetConnection (alias tnc) that provides a subset of nc's features.
go to post Jeffrey Drumm · Mar 7, 2023 Something like this, perhaps? Class User.Util.StringFunctions Extends Ens.Util.FunctionSet { ClassMethod ReReplace(pStr As %String, pPat As %String, pRepl As %String = "") As %String { Set tStrt = $LOCATE(pStr,pPat,,tEnd) - 1 // in case the pattern isn't found, return source string Return:(tStrt < 0) pStr Set tPrefix = $EXTRACT(pStr,1,tStrt) Set tSuffix = $EXTRACT(pStr,tEnd,*) Return tPrefix_pRepl_tSuffix } } USER> set mystr = "REASON->Blood(1.23)" USER> set newstr = ##class(User.Util.StringFunctions).ReReplace(mystr,"->\w+") USER> write newstr REASON(1.23) USER> set altstr = ##class(User.Util.StringFunctions).ReReplace(mystr,"->\w+","-CODE") USER> write altstr REASON-CODE(1.23)
go to post Jeffrey Drumm · Oct 21, 2022 Hi Blake, This might get you started in the right direction: Set tRuleName = "<rulename>" Set tTarget = $ORDER(^Ens.Rule.Targets(tRuleName,"")) Set tArr = 0 Set tCnt = 1 While tTarget '= "" { Set tArr(tCnt) = tTarget Set tTarget = $ORDER(^Ens.Rule.Targets(tRuleName,tTarget)) Set tArr = tCnt Set tCnt = tCnt + 1 } Replace <rulename> with the name of the rule as it appears in the router configuration pane.
go to post Jeffrey Drumm · Sep 26, 2022 There's a self-paced training session on BPLs here; it should help get you started. Can you describe the routes that the ADT and ORM messages are taking to get to the downstream system? Are they coming in through different services and/or being delivered downstream over different operations?
go to post Jeffrey Drumm · Sep 23, 2022 A BPL is a Business Process class, so you would add a new Process to your production and select the name of the BPL you created as the class (rather than, say, a routing engine).
go to post Jeffrey Drumm · Sep 16, 2022 With some help from a fellow DC member, I wrote the method below. Its intent is to support auto-resolution of managed alerts: /// Returns the connection status ("AdapterState") of the Business Service or Operation /// named in <var>pItemName</var> ClassMethod GetConnectionStatus(pItemName As %String) As %String [ Language = objectscript ] { Set tStatement = ##class(%SQL.Statement).%New() Set tStatus = tStatement.%PrepareClassQuery("Ens.Util.Statistics","EnumerateJobStatus") If $$$ISERR(tStatus) { Return "Error in Status Query: "_$system.Status.GetErrorText(tStatus) } Set tRS = tStatement.%Execute(pItemName) If tRS.%SQLCODE = 0 { Do tRS.%Next() Return tRS.%Get("AdapterState") } Return "Status not Found" }
go to post Jeffrey Drumm · Aug 8, 2022 Here's a little code snippet that the Management Portal uses to get the Arbiter state: Set state = $SYSTEM.Mirror.ArbiterState() Set thisConnected = $SELECT($ZB(+state,+$$$ArbiterConnected,1)'=0:1,1:0) Set otherConnected = $SELECT($ZB(+state,+$$$ArbiterPeerConnected,1)'=0:1,1:0) If 'thisConnected { Set stateString = $$$Text("This member is not connected to the arbiter") } ElseIf 'otherConnected { Set stateString = $$$Text("Only this member is connected to the arbiter") } Else { Set stateString = $$$Text("Both failover members are connected to the arbiter") } You'll need to add an Include statement for %syMirror to use the $$$Arbiter* macros. Note that the ArbiterState() method is undocumented, and its behavior may change in future releases.
go to post Jeffrey Drumm · Jul 21, 2022 Not sure why yours is showing OpenSSL v3. I'm running IRIS for Health 2022.1.0.209.0 on a Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-121-generic x86_64) physical host and I had no issues with installation. My guess is that it isn't really complaining about openssl, but that libssl isn't at least version 1.1.1. I'd try running (as root): # apt install openssl # apt install libssl1.1 These commands should install pre-compiled binaries. The first one should automatically install openssl 1.1.1f and the 2nd the same version of the libssl libraries. And yes, while I haven't specifically used VirtualBox, I am a long-time user of VMWare on multiple platforms, with multiple Linux guests and versions of Caché/IRIS. Virtualization has, so far, very rarely been an issue.
go to post Jeffrey Drumm · Jul 20, 2022 It's a bug, and InterSystems is aware. It's still present in 2022.1, but I expect it will be fixed in an upcoming release. For now, you'll need to change the resource associated with the database(s) to %DB_%DEFAULT (or whatever you prefer) after the creation of the namespace. That can be done through the management portal, under System Administration | System Configuration | Local Databases.
go to post Jeffrey Drumm · Jul 13, 2022 At some point I encoutered a problem that required I also run this command: setsebool -P httpd_unified 1 I can't remember what it fixed, but I do know by the fact that I made a note of it that it fixed something ...
go to post Jeffrey Drumm · Jun 6, 2022 Yes, in retrospect I should have realized that the DocType Structure was what the constraint required rather than the calculated value in the Name property. Sorry for any head-scratching I might have caused
go to post Jeffrey Drumm · Jun 6, 2022 You shouldn't need to ... DEV>Set msg = ##class(EnsLib.HL7.Message).%OpenId(29485840) DEV>Write msg.Name ADT_A11 DEV>Write msg.GetValueAt("MSH:9") ADT^A11 DEV>Do msg.SetValueAt("A08","MSH:9.2") DEV>Write msg.GetValueAt("MSH:9") ADT^A08 DEV>Write msg.Name ADT_A08 But I guess it wouldn't hurt Is it possible that there's an action somewhere in the DTL that clears MSH:9?
go to post Jeffrey Drumm · Jun 1, 2022 I've written a query for HL7Spy's SQL Loader that extracts ACKs/NAKs from the IOLog: Here's the SQL in text form. The method HICG.GetMsg() is an ObjectScript stored procedure written specifically for HL7Spy that returns the message body as a stream for delivery via ODBC. You could adapt the SQL for use with the %SQL.Statement class to return a result set containing the message body IDs, Next() your way through that, open each message with %OpenId() and write it out to a file. Getting just the NAKs will require a bit of message parsing. SELECT head.ConfigName As ConfigName, body.DocType As DocumentType, body.Name As BodyName, HICG.GetMsg(body.ID) As Message FROM Ens_Util.IOLogObj head INNER JOIN EnsLib_HL7.Message body ON head.InObjectId = body.%ID WHERE -- specify start and end time for search here head.ID >= (SELECT TOP 1 ID FROM Ens_Util.IOLogObj WHERE TimeReceived >='2022-06-01 00:00:00.000' ORDER BY TimeReceived ASC) AND head.ID <= (SELECT TOP 1 ID FROM Ens_Util.IOLogObj WHERE TimeReceived <='2022-06-02 00:00:00.000' ORDER BY TimeReceived DESC) AND head.IsInbound = 0 AND head.InObjectClass = 'EnsLib.HL7.Message' AND head.ConfigName = 'To_Outbound_Operation' -- substitute operation name here
go to post Jeffrey Drumm · Apr 29, 2022 Assuming you cut and pasted from your DTL, the double-quote characters around the 2nd dash are incorrect. They appear to be the distinct open and close quote characters that Word automatically substitutes for the "standard" double-quote character: set tSSN source.{PID:SSNNumberPatient} set target.{PID:SSNNumberPatient} $E(tSSN,1,3)_"-"_$E(tSSN,4,5)_”-“_$E(tSSN,6,9)