Jeffrey Drumm · Oct 27, 2021 go to post

@Alexander Koblov, can you clarify the relationship between the JDBC Gateway and the SQL Gateway Connection option for JDBC? Is the JDBC Gateway the same thing as the %JDBC.Server located under External Language Servers in IRIS 2021.1, since there is no "JDBC Gateway" menu option in the Management Console?

I'm currently attempting to set up a JDBC SQL Gateway connection for MSSQL Server and am unable to get the  jre16 (or jre8) driver to load. OpenJDK 1.8 is installed, JAVA_HOME is set, $JAVA_HOME/bin is in the path, and IRIS has been restarted. We're running IRIS/HealthConnect on RHEL 8.4. I noticed that when clicking the "Test" button in the connection configuration page that the %JDBC.Server is started before getting the error "Connection failed. The driver cannot be loaded" so there appears to be some relationship between the two, but even with logging turned on I'm not seeing any reference to the MSSQL driver's failure to load.

Jeffrey Drumm · Oct 26, 2021 go to post

Do you have a space character between the ! and SFTP in your service settings? You shouldn't ... I'm not sure that's related to the problem you're having but that's the first thing I would fix.

Can you establish a connection to the target system from the HealthConnect server itself, using the command-line sftp utility? I believe you mentioned FileZilla in another post, but it wasn't clear that you were attempting to connect from your own desktop or the HealthConnect server itself (which I suppose could be the same thing for a local, personal installation).

Finally, to be clear, you've created a Credentials entry in Ensemble (Interoperability in most recent versions) | Configure | Credentials, called something other than !SFTP, that contains the user ID and password for the remote system? And you've specified that entry name in the Credentials field? You mention "login information in Basic Settings" which I would assume means credentials, but I just want to make sure ...

Jeffrey Drumm · Oct 25, 2021 go to post

In the latest versions of HealthConnect/IRIS for Health, sftp is now a specific protocol that can be selected from a drop-down list in the Connection Settings section. And if you are on one of the latest versions, make sure you're selecting the correct Credentials field as there are two: Credentials in the Basic Settings section, and SFTP Passphrase Credentials in the SFTP section. The former is where you want your logon user ID and password credentials selected; the latter is specifically for the passphrase used to unlock the private key when using public/private key authentication. It does nothing for SFTP password-based authentication.

Jeffrey Drumm · Oct 19, 2021 go to post

PID:3 is a list, meaning it has the potential to contain multiple ID numbers separated by the repetition character (normally a tilde). If you only want the first ID number to appear on the target field, don't use a for each loop. Just use a single set rule as shown below:

Note that there's no repetition indicator in the target path, and we're selecting the first repetition in the source:

Jeffrey Drumm · Oct 18, 2021 go to post

Sure, just set the value of target.{PID:3} to source.{PID:3.1}. It will overwrite the entire field with just what was in the first sub-field:

Like this (assuming you want the first iteration of PID:3.1 to overwrite all iterations of PID:3):

Jeffrey Drumm · Oct 18, 2021 go to post

I don't have access to Ensemble 2013.1, unfortunately.

I'm not seeing anything that looks like a Serial adapter/service in the most recent versions of Ensemble/HealthConnect, though. Is the inbound service a custom class? (EDIT: Subject mentions TCP, but reply still mostly applies).
You should be able to extend the class, replacing the $C(13) character with $C(13,10) in the the OnProcessInput() callback method before sending the message to the routing process.

Jeffrey Drumm · Oct 10, 2021 go to post

I will add that I am very grateful to ISC for finally adding this foreach feature to the routing rule functionality (it appears to have become available with 2020.4). I have one quibble, though ... it would be wonderful to be able to exit the loop without returning from the ruleset (i.e. "break"). The current mechanism forces you to loop through all repetitions regardless of the desired condition being met before the final loop iteration is reached.

A design pattern where I might wish to assign a value to a variable and exit the loop when the condition is met (rather than executing a send) is something I can envision doing regularly.

Jeffrey Drumm · Oct 9, 2021 go to post

Are you correctly specifying the propertypath for the Document Type of the message? This works as expected for me, where the DocType is 2.5:ORU_R01:

Jeffrey Drumm · Oct 7, 2021 go to post

The square bracket notation returns a string containing all of the values for the selected field in the repeating segments, each wrapped in "<...>" characters.  So the Length() check is returning false ...

This should be closer to what you need:

Jeffrey Drumm · Oct 7, 2021 go to post

If you're attempting to determine whether the same value appears in a field for all repetitions of a given repeating segment, the ..RegexMatch() function, virtual document bracket syntax and an appropriately constructed regular expression should be able to handle this:

EDIT: My original example included a caret ("^") as the regex begin string anchor, but it appears the RegexMatch() method forces the pattern the pattern to be begin and end anchored. In other words, the pattern supplied as the 2nd argument is automatically wrapped with "^" at the beginning and "$" at the end. You can add them if you like, but doing so doesn't change the behavior.

Jeffrey Drumm · Oct 6, 2021 go to post

I would assume that @Jonathan Lent has a scheduled purge job in Task Manager; ISC ships HealthConnect with one (Ens.Util.Tasks.Purge) that can be configured for a retention period, along with a few other settings:

If he's overriding the OnDelete method, I suppose it could be used to delete the on-disk file.

Jeffrey Drumm · Oct 2, 2021 go to post

So, on re-reading your question and looking at your example, I'm wondering whether you really wish to check whether the fields are empty, or that they contain more than 1 character? A single character value isn't "empty" and your expression will return true if either field has zero or 1 character in it.

If you're simply checking for a condition where both fields are empty, this is a solution:

'(..Length(source.LABRSLTNUMRSLTVAL) && ..Length(source.TSTRLTVAL))

Or this, which is a bit closer to what you had come up with:

'(..Length(source.LABRSLTNUMRSLTVAL)) && '(..Length(source.TSTRLTVAL))

A non-zero numeric return value evaluates to true, so no need to provide a comparison operator for the individual length checks.

Jeffrey Drumm · Oct 2, 2021 go to post

Hi Ed, it appears to be the '>1 expression. Try using =0 instead, or perhaps <1.

Syntactically the '>1 logical construct is valid, but to me seems unconventional when there's a single logical operator that performs the exact same function.

Jeffrey Drumm · Oct 1, 2021 go to post

The EnsLib.* classes don't have inherent categories. You can certainly add a Category property to classes that you create, though.

Jeffrey Drumm · Oct 1, 2021 go to post

Multiple Production Items will use the same class (for example, the HL7 TCP Services/Processes), and categories are a Production Item property. You would need to determine first which items are using that class, then get the categories from those items.

Is that what you're looking to do?

Jeffrey Drumm · Sep 27, 2021 go to post

The "easy" options indicated by the source code do some interesting things, but showing %IO* isn't among them. I'll keep looking wink

Jeffrey Drumm · Sep 27, 2021 go to post

Is there a special trick to making %IO visible? Selecting the "Percent Classes" checkbox doesn't do it.

Jeffrey Drumm · Sep 24, 2021 go to post

There's the Export() method in Security.Users ...

%SYS> set sc=##class(Security.Users).Export("/path/to/exportfile.xml")

Documentation is here.

Jeffrey Drumm · Sep 24, 2021 go to post

Yes, in the %SYS namespace you can use the ^SECURITY utility. The export will be in XML format.

USER> zn "%SYS"

%SYS> d ^SECURITY

1) User setup
2) Role setup
3) Service setup
4) Resource setup
5) Application setup
6) Auditing setup
8) SSL configuration setup
9) Mobile phone service provider setup
10) OpenAM Identity Services setup
11) Encryption key setup
12) System parameter setup
13) X509 User setup
14) KMIP server setup
15) Exit

Option? 1

1) Create user
2) Edit user
3) List users
4) Detailed list users
5) Delete user
6) Export users
7) Import users
8) Exit

Option? 6
Jeffrey Drumm · Sep 20, 2021 go to post

Assuming you have the service pointed in the right direction, there may be something wrong in either the configuration of the router or the rule itself.

The relevant configuration details from the "General" tab of the rule:

And a basic example of how you'd create a rule based on field criteria:

Jeffrey Drumm · Sep 20, 2021 go to post

Hi Doug,

If you're creating a Busness Process to route/translate RecordMap messages, you'll want to use EnsLib.MsgRouter.RoutingEngine as the BP class. It doesn't expect a document type, unlike the VDoc class.

EDIT: I should have also mentioned that there's no need to select a document type for the RecordMap in the DTL editor, since they don't have one laugh

Jeffrey Drumm · Sep 18, 2021 go to post

Hey Doug,

It's been a very long time :)

So ... no, you don't need a complex record map to do this, but the mechanism takes just a little more work using a "simple" record map. The record map feature doesn't let you set a Composite field as repeating, which is why we need to deal with those "grouped" OBX segments/fields using a different method.

What I've done is define the RecordMap with individual fields for everything before the first OBX field, and then define the rest of the record as a single, repeating field. You can then iterate over that last field and parse out the individual HL7 field values with $PIECE, or turn them into a $LIST and  reference the elements by numeric index. The only delimiters you'll need to set for the record map are a "|" as the field delimiter and a "~" for the repetition delimiter.

Here's a sample record map layout:

Along with setting OBXSegs as repeating, I set the MAXLEN DataType parameter to something large enough to accommodate all of the fields. Also note the Discard field; the sample data in your post included a leading "|," so that needs to be treated as though there's an initial empty field in each record. Including a dummy field to consume it makes things a bit more understandable when addressing the subsequent fields.

Here's one way you might iterate over the repeating record map field:

As you surmised in a follow-up to Nora's earlier posts, the Complex Record Map functionality is really only required when the record structure varies from line to line in the input data.

Jeffrey Drumm · Sep 7, 2021 go to post

Have you looked at the Default Char Encoding setting of the various HL7 operations? 

Jeffrey Drumm · Aug 25, 2021 go to post

It's not normally a property of the message header or body objects. You can often find the port number in the Source property of the Body, but not the IP address. To get that, you'll need to look at the Event Log for the service. It will look something like this:

As for what you're doing wrong ... hard to say at this point; not much to go on. Does the connection complete successfully without restricting the allowed IP addresses?

Jeffrey Drumm · Aug 25, 2021 go to post

I don't believe this is possible without assistance from the training team at InterSystems.

Jeffrey Drumm · Aug 20, 2021 go to post

There are two steps to this ... the first is to open the file as a stream of type %Stream.FileBinary, the second is to use the EnsLib.HL7.Message method StoreFieldStreamBase64() to insert the stream into the desired field.

EDIT: The links point to earlier versions of Ensemble's class methods but they're still valid.

Jeffrey Drumm · Aug 18, 2021 go to post

Interesting that it works in the opposite direction:

USER> w $zconvert("Fl&aacute;vio","I","HTML")
Flávio
Jeffrey Drumm · Aug 15, 2021 go to post

Put them in a separate production and namespace that is restricted to only users with the proper role/resource assignments. There is no built-in mechanism to restrict visibility below the production/namespace level.