Markus Mechnich · Dec 18, 2017 go to post

Hi Motti,

in some projects we faced similar situations. We finally took as Sean mentioned as #2  the Enterprise Message Bank solution and spent some effort in having build specialised SearchTables  - which are populated through Ens.Enterprise.MsgBank.BankHelperClass and implement its OnBankMsg().

The regular message searches are now done in the MessageBank.

And sure, some custom purge methods would help to leave everything in one namespace as you mentioned.

Kind regards,

Markus

Markus Mechnich · Feb 21, 2017 go to post

From a technical point Eduard mentioned the most straight forward way.

Another option would be to subclass EnsLib.File.OutboundAdapter. Having only one Put* call.

There for you may introduce a SecondFilePath setting. Overwriting the Put* methods using ##super() could then easiliy produce more than one filecopy.

Markus Mechnich · Feb 20, 2017 go to post

Yes, the web wizard uses the Display Format in this case.

It can be adjusted through the Format Parameter:

"The format specification for the data type's display value. The value of the FORMAT parameter corresponds to the available parameters of the $ZDATE and $ZDATEH functions, which are used to perform the formatting. " [Online Documentation]

Markus Mechnich · Jan 11, 2017 go to post

This is how the LookupTable is projected to a Studio Document:

 <?xml version="1.0"?>
<lookupTable>
<entry table="TestLookupTable" key="T1">V1</entry>
<entry table="TestLookupTable" key="T2">V2</entry>
</lookupTable>
Markus Mechnich · Jan 11, 2017 go to post

Import the exported LookupTable with $system.OBJ.Import() or any means available like Studio or System Management Portal.

Markus Mechnich · Jan 11, 2017 go to post

Packaging a LookupTable within a project:

Include the "*.lut" in a Studio Project. Then the LookupTable can be exported with other relevant development objects.

Markus Mechnich · Jan 11, 2017 go to post

Export via $system.OBJ.Export(<LookupTableName>,<FilePath and FileName>).

The extension is ".lut". A LookupTable "TestLookupTable" can be exported as follows:

 write $system.OBJ.Export("TestLookupTable.lut","c:\temp\lut1.xml")
Markus Mechnich · Dec 12, 2016 go to post

In typical scenarios you'll find SNMP to be used for Error Alerting .
SNMP Traps can be issued from the Ensemble installation and send to a centralized monitoring (As far as documentation of Splunk shows it does support SNMP). 

MIB's are also available for monitoring via SNMP. In your case you could think of extending the MIB to support your information requirements (http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_snmp#GCM_snmp_mib_extend). 

Ensemble further supports WS-Management API http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_wsmon.

Markus Mechnich · Dec 12, 2016 go to post

Inside of a MessageRouter you can refer to Document.Source
For a HL7-MessageRouter it can also expressed (as you mentioned in your comment) HL7.Source.

EnsLib.HL7.MessageRouter.RoutineEngine implements:

Method HL7Get() As EnsLib.HL7.Message [ CodeMode = expression ]
{
..Document
}
 

Markus Mechnich · Dec 11, 2016 go to post

The following way might be handy for a one time import.

The ClassMethod %UpdateValue() in Ens.Util.LookupTable is to Update or Insert Entries:
Copying from Excel and pasting it to Terminal (Shift-Insert) will result in Tab delimited Key Value pairs.

The following commands insert one entry into the LookupTable "mytable":

ENSEMBLE>read line
ENSEMBLE>write ##class(Ens.Util.LookupTable).%UpdateValue("mytable",$P(line,$C(9)),$P(line,$C(9),2)

Copying a series of Values directly from Excel might work as follows.

Looping in Terminal using the above idea would be a one line:
ENSEMBLE>do {read line  if line'="" {write ##class(Ens.Util.LookupTable).%UpdateValue("mytable",$P(line,$C(9)),$P(line,$C(9),2),1)}} while line'=""
Markus Mechnich · Dec 10, 2016 go to post

There are multiple ways as Bredan also pointed out.

If you're Excel specialist ;-) you might want to introduce a third column.

Use the CONCATENATE string function or whatever it is called in your Excel version.

The following will lead to a XML entry which you could copy & paste in an standard XML Export of a lookup table,

So just mockup a Lookiup table, export it. Modify the file with the new entries and Import the resulting file.

Just 2 other cents,

function GER =VERKETTEN("<entry table=""TestLookupTable"" key=""";B2;""">";C2;"</entry>")
function ENG =CONCATENATE("<entry table=""TestLookupTable"" key=""";B2;""">";C2;"</entry>")
T1 V1 <entry table="TestLookupTable" key="T1">V1</entry>
T2 V2 <entry table="TestLookupTable" key="T2">V2</entry>
T3 V3 <entry table="TestLookupTable" key="T3">V3</entry>
T4 V4 <entry table="TestLookupTable" key="T4">V4</entry>
Markus Mechnich · Jul 15, 2016 go to post

Troubleshoot #1

Just in case you find a java UnsatisfiedLinkError...
It seemed that the test installation wrongly choose the 32-bit version.
It was solved on my maschine by reinstalling the Java JRE 64 bit.

This was on Java(TM) SE Runtime Environment (build 1.8.0_92-b14).

java.lang.UnsatisfiedLinkError: C:\....\sapjco3.dll: Can't load AMD 64-bit .dll on a IA 32-bit platform
Markus Mechnich · Jul 14, 2016 go to post

Just a play:

Here you're having a counter which counts within the terminal's same line

SAMPLES>for i=1:1:10 hang 0.5 write $C(13),?10,i
          10

Markus Mechnich · Jul 14, 2016 go to post

For reporting as asked in the heading we have standard mechanisms which where already mentioned.
Of course you might want to be more flexible (less standard). Then you might query the virtual documents in scripting directly and act very flexible on errors.

If there has been tried to build a map (correlation to a schema) with the VDoc method BuildMap() the virtualDocument.BuildMapStatus on that virtualDocument is available. This is how the Message Router decides on map errors.

Markus Mechnich · Jun 13, 2016 go to post

It looks as  for $-notation one needs some DocType to be available, at least this is what %objlasterror tells.
Using [] you might get what you expect.

ENSEMBLE>write !,vDoc.GetValueAt("$1")
ENSEMBLE>write %objlasterror
0 ñ<Ens>ErrGeneral:Can't evaluate property path because DocType  is not set
                                                                             ENSEMBLE,e^zpropParsePath+2^EnsLib.EDI.XML.Prop.1^1-e^zpropGetValueAt+3^EnsLib.EDI.XML.Prop.1^1.e^zGetValueAt+16^EnsLib.EDI.XML.Document.1^1e^^^0

Variants with []-notation:

ENSEMBLE>write !,vDoc.GetValueAt("/Body/[2]")
30
ENSEMBLE>write !,vDoc.GetValueAt("/[1]/[2]")
30

Markus Mechnich · Jun 9, 2016 go to post

The internal structure of EnsLib.SQL.Snapshot allows an easy direct access to the current row as a Listbuild using EnsLib.SQL.Snapshot.GetRowList(). This could be used to calculate a hash, but you would need to manage this in the business host's code. Because the amount of data to transport is not in all cases small I would suggest or evaluate the following approach:
 Obviously it is not that easy to judge whether a row from an external db has changed or not. The easiest approach if possible at all in such scenarioes would be to ask for an additional field in the external database table which gets filled on the external database side with an last update timestamp or a version id (like Caché has for objects). Then the SQL statement could honor only the new/changed records. This would minimize the amount of data to transport compared to the orignal proposal.

Markus Mechnich · Jun 8, 2016 go to post

This is an excellent overview with easy to understand examples.

Walking through it I foundthat the "WriteUpdateToTargetDB" method is concatenating the SQL-String which then gets executed against the external database. 

Even if this is just an example it would allow a possible attack of a 2nd order sql injection - if the attacker has knowledge of the system. The easiest way to be more secure is to use placeholders in the sql statement and parameters when calling the external database.
Another advantage of using placeholders is that there is no need for quotation marks.
 

Markus Mechnich · Jun 7, 2016 go to post

If you disable the Business Operation you will see e.g. the XML file in the message browser.
The inbound file adapter doesn't delete the stream as long as it is in transit.


As far as I know there is no explicit storage in the Ensemble database for long term availability.
As soon as the Business Operation has **successfully** written the stream to it's device the incoming stream is deleted. 
To archive the incoming file in the filesystem, use the setting ArchivePath. To be able to work asynchronously with the business operation look at the setting WorkPath.

To have permanent view to the stream content it would be needed to be available. You might think of building your own message class and inherit from the Passthrough Service. The Passthrough Operation uses the property named Stream in its Request Message.  But be careful with the potential needed amount of storage. The current implementation is intended to achieve a high throughput.


Regards,
Markus

Markus Mechnich · Jun 4, 2016 go to post

In the IHE context I onced faced the scenario that there was no given encoding in the XML declaration.
The rule was to use in such a case the character encoding which could be found in the HTTP HEADER.

For example: Content-Type: text/html; charset=utf-8