David Loveluck · Apr 12, 2017 go to post

I don't think your code is wrong per se, but you are using a variable tSC that is used elsewhere as a status value.

If you skip the assignment to tSC and put it straight into Target.text you will probably be ok.

David Loveluck · Mar 31, 2017 go to post

I think the only property that can be used to create the filename is Source which contains the original file name. That is included by specifying %f in the output file.

You *could* steal that and put the value of MSH-4 in HL7.Source in some DTL in the routing engine.

Hijacking fields is never elegant and it can always bite you later when someone tries to use it for its original purpose, but ...

David Loveluck · Mar 22, 2017 go to post

There was a nationwide project in the UK a number of years ago and i believe there have been several more but i don't know the details.

Having said that, it is a very wide ranging standard so there is no guarantee that the pieces you want are covered by that project.

Also, when i last looked at this several years ago, it was widely agreed that the standard was dead, having slowly collapsed under its own weight (although some elements live on in other standards).

I don't know if ebXML has been revived in recent years, but I doubt it. Why are you interested in it?

David Loveluck · Aug 22, 2016 go to post

I think that validating data types across the board in Ensemble is only useful in a few specialist situations, such as building an HL7 clearing house. It is expensive and often gets in the way of what you really want to achieve.

What downstream applications will successfully handle in messages is often very different to the published standard and most people will focus on validating particular fields that are important to their environment rather than adherence to the standard.

In the case of TN the early HL7 schemas defined it as a string, but added no structure or length restrictions so it added no value other than documenting for applications that this field was expected to be a phone number. It seems to have gone from HL7 2.5 and later.

Dave

David Loveluck · Aug 17, 2016 go to post

strictly speaking Ensemble is a separate product. DeepSee is the BI technology that is included in both Cache and Ensemble. Some functionality of DeepSee needs extra license options.

David Loveluck · Aug 10, 2016 go to post

Yes, credentials are defined in each namespace. It would be possible to map the relevant globals to a single shared database but that would add a piece of complexity that is more likely to hurt than help.

My **guesses** are that either your email server is not set up securely in your test environment and is accepting input anyway, or that you have some OS level authentication going on, or most likely you have configured an SSL configuration to use to connect to the email server and the username/password or certificate are part of that.

David Loveluck · Jul 22, 2016 go to post

there is a thread about class queries that gives a full explanation but in this specific case you could do ...

   set statement=##class(%SQL.Statement).%New()
    set status=statement.%PrepareClassQuery("%SYS.GlobalQuery","Size")
   set resultset=statement.%Execute("c:\intersystems\ens20163a\mgr\ensemble","","*")
    while resultset.%Next() {
        write !, resultset.%Get("Name"),", "                                       
        write resultset.%Get("Allocated MB"),", "    
        write resultset.%Get("Used MB")
     }

David Loveluck · Jul 18, 2016 go to post

In Ensemble or HealthShare there is a class for the HL7 segments but it is not a persistent class so it is not exposed to SQL. The segments are stored in raw globals for speed and the virtual document paths are  parsed at run time for efficiency. 

You can use the message browser to look for messages where a particular segment/field value has a given value. But if you look at the generated SQL it doesn't seem to make sense. That is because the SQL query is used in a cursor and the access to segment values is done in COS inside the cursor iteration.

If you can be more specific about what you are trying to do i might be able to give you some pointers about how to get where you want to go.

David Loveluck · Jun 29, 2016 go to post

you have to be on 2015.1 to have a pure DTL transform of an X12 interchange.

On 2014.1 you will have to use object script to loop over the child documents of the interchange to get the groups and then loop over the child documents of the groups to get the  actual documents. I can't find an example right now, but hopefully another reader can point you to one. 

David Loveluck · Jun 28, 2016 go to post

Laura

your sample file is a an interchange (look for the ISA and IEA segments) that include one group (see the GS and GE segments) that in turn contains one 835 message (look for the ST and SE segments).

An interchange can contain multiple groups which typically contain many individual transactions.

You should just copy the ST and SE segments and all in between and use that to test your 835 transformation.

You can then create transformations on the interchange and the group and loop through all the individual transactions calling your DTL as subtransformations. I think this is documented but it has got easier in the last few years so hopefully you are on a modern release.

Alternatively, because people want the same simple changes to the interchange and group segments for all X12 transactions people often just write than bit in object script.

Ask again if you don't find the documetnation

dave

David Loveluck · Jun 22, 2016 go to post

it is intended for constant collection of statistics from a live system.

To minimize the overhead, the counts are accumulated in memory and written to disk at intervals. Benchmarks showed no significant increase in resources consumed with statistic gathering turned on.

This means the package avoids anything that would be relatively expensive to collect. For example several people have asked for the average size of a message to be collected but this would have needed an extra method call to get the information.

It also means that the statistics are not guaranteed to be correct if the system crashes.

David Loveluck · Jun 21, 2016 go to post

With 2015.1 and later you have the option to increase the rule logging. This will tell you exactly what is going on when executing a routing rule. 

There is a setting in the Development & Debugging section of the configuration settings of a routing engine. That is described as ...

This set of flags controls the logging performed by the rule engine whenever a routing rule is executed. The following flags are available:

  • 'e' - log errors only. All errors will be logged irrespective of other flags, so setting the value to 'e' or leaving the value empty will only log errors.
  • 'r' - log return values. This is the default value for the setting, and is also automatic whenever the 'd' or 'c' flags are specified.
  • 'd' - log user-defined debug actions in the rule. This will also include 'r'.
  • 'c' - log details of the conditions that are evaluated in the rule. This will also include 'r'.
  • 'a' - log all available information. This is equivalent to 'rcd'.

Dave

David Loveluck · Jun 10, 2016 go to post

As Liz says this feature has been in Ensemble for about ten years. One very obvious use case in development is to have a file based BO as a duplicate of a TCP BO so you can cut out all the complexity of testing with a real target system.

To add a duplicate you just add another config item to your production with the same name.

Whichever one is selected from the pull down will start up with the production.

To remove a duplicate you select the one you want to delete from the pull down and delete the config item from the production. The other one will be left behind. Or you could edit the XML to remove it.

David Loveluck · Jun 2, 2016 go to post

I looked at the code and StatsStarted returns 1 if InitStats has been called within the current business service. So it is more than statistics being enabled for that config item.

I will get someone to look at the sample code.

David Loveluck · Jun 1, 2016 go to post

Hi James

i don't know exactly what you are doing so i'll give some background and you can ask more questions.

InitStats initializes the local counters. Like resetting and starting the stopwatch.

RecordStats takes the values since InitStats and adds them to the temporary array.

The framework call these two for you. For example Ens.BusinessService.ProcessInput() of a business service calls them to capture the activity of a single invocation of a business service.

If you want to capture stats in your own code you can call them yourself.

If you have called SetStatsUserDimension between the two then that value is put in the userdimension field. For example, if my application has a business service that is accepting orders for widgets then in OnProcessInput I might have the line

     do ##class(Ens.Util.Statistics).SetStatsUserDimension(..%ConfigName,pInput.Color)

and I would be able to get a breakdown of statistics for black, blue or green widgets

If you want to use your own statistics instead of out elapsed time and count, you can use RecordStats to write whatever values you like to the temporary array.

StatsStarted() is supposed to be used to check that statistics gathering has been turned on for the production or config item. For now, just don’t use it and assume the stats are turned on. I will find out more.

I don’t remember what StatsActive() means you probably don’t need to call it. I have never used it.

Dave

David Loveluck · May 19, 2016 go to post

It doesn't change this discussion but for many years we have documented that a proper web server such as IIS or Apache  and CSP should be used instead of the  http inbound adapter in any operational setting.

That provides a level of operational robustness (security, recovery etc.) that the inbound adapter will not provide.

dave 

David Loveluck · May 13, 2016 go to post

I think you might be getting local times and UTC times mixed up.

TimeCreated is stored in UTC and now() gives you local time so your arithmetic could be giving a negative number

Dave

David Loveluck · Apr 27, 2016 go to post

Thanks Clayton. 

Overriding OnConstructReply like this is very useful for constructing  non standard ACKs in the HL7 world as well.

David Loveluck · Apr 22, 2016 go to post

Richard

welcome to the community. I think you are misunderstanding a few things and making life hard for yourself. If you are just processing HL7 messages you probably don't need to do any coding until you get to more advanced topics. The graphical editors will do nearly everything you need.

I suggest you watch the  getting started videos at

http://video.intersystems.com/video/Video.Pages.VideoLibrary.cls?video=…

below the first video there is a playlist of  topics including one on transformations. Notice that there is an odd shaped arrow to the right of the three playlist items visible on the screen so you can scroll across and see the others,

You can probably watch all seven videos in about an hour and you will be ready to start.

Enjoy

dave

David Loveluck · Apr 21, 2016 go to post

Jeff

several points:

1) Extending EnsLib.SOAP.Service is absolutely fine as long as you  make sure it uses CSP and not the HTTP Inbound Adapter. We are trying to remove all references to that adapter from our examples but it is taking a longer than i had hoped.

2) In general,for creating a SOAP service that is not just a pass through (or close to pass through)  i normally prefer to just extend %SOAP.Service and keep the  business service definition separate. It means you have to do a small amount of extra work, but you also get more control. It is a matter of personal preference.

3) For pass through you should probably use the EnsLib.xxxx.GenericService where xxxx is one of REST, HTTP or SOAP. These bundle up additional information such as the http headers so the  outbound request faithfully reproduces the inbound request.

4) And finally if you want to gain efficiency by reducing the overhead of persistent messages within Ensemble you should look at the new features included in 2015.2. For these pass through cases you can now user real inproc calls and suppress all the message storage and journal creation. This makes it more efficient but you lose the message trace.

release notes:

http://docs.intersystems.com/documentation/ensemble/20152/pdfs/EGRN.pdf

detailed documentation:

http://docs.intersystems.com/ens20152/csp/docbook/DocBook.UI.Page.cls?K…

David Loveluck · Apr 21, 2016 go to post

This is a very good question but there are some subtleties that need to be considered.

On a production server, compilation should be part of a managed deployment process so this isn’t an issue, but in development it is easy to forget to restart a BS or BO.

This situation only applies to Business Services and Business Operations. Typically in a BS or BO the class that implements the service remains instantiated until the BS is disabled or the production is restarted and so the old code runs. The Business process class is instantiated for each request so it doesn’t apply there.

It can be more complicated. For example if a BS is instantiated by application code using CreateBusinessService() from (for example) a web page the BS class will be instantiated for each request so you will see the new code picked up immediately. On the other hand if one job in a pool dies and is restarted, or if the pool size is increased, then you can have a mixture of BS jobs, some running the old code and some running the new code. This is probably rare in development but I do know someone was confused by that situation a few years back.

The configuration page that shows connections can’t know what code is instantiated in running Business Services and the connection lines have to be derived from the current code in the class definition. The only thing that could be done with that is to disable the functionality if the class has been compiled; but that would be unhelpful in the cases when the change had nothing to do with routing.

If a BS or BO continues to run older code after the class is compiled, then we log a message in the event log. We might be able to set a flag in the Job Status global and have an indication in the production monitor based on that, but this situation exists on a job basis, not on a configuration item basis so the UI would be a compromise in the special circumstances described above. I have recorded the enhancement request but nothing is currently planned so for now, I would always advise restarting a BS or BO as soon as you compile the class.

David Loveluck · Apr 14, 2016 go to post

Steve

do you just mean that the recipient is responsible for opening the TCP/IP connection? You can make that happen by putting ! in front of the TCP/IP address of the target

Dave

David Loveluck · Mar 29, 2016 go to post

this is data captured as a result of setting 'archive IO' on a BS or BO.

There is no UI to view the IO log but if you search the documentation for IOLog it will tell you the SQL query to use.

For adapters this is intended to capture information close as close to being the information sent over the wore as possible. However, for many technologies (e.g. CSP or xDBC) that is not very close and there are better ways to capture the information sent over the wire, so this is not as widely used as it once was.

I don't know why it wouldn't be purged if the time created is old enough for you to expect it to be purged.

David Loveluck · Mar 14, 2016 go to post

i thought a routing engine was the harder case :-)

If you are in COS called from BPL then you can access the current BP as 'process' as long as either

a)you do not use the ProcedureBlock class keyword,

or

b) you put process in the public list for you method

then you can access properties of the process such as %PrimaryRequestHeader

ClassMethod MyMethod(vale As %String) As %String [ PublicList = process]

{

   ...

  set src=process.%PrimaryRequestHeader.SourceConfigName

   ...

}

If you are calling a COS funciton from a routing rule, you can get similar information form the variable 'context' which is a reference to an object of type EnsLib.HL7.MsgRouter.RoutingEngine 

David Loveluck · Mar 14, 2016 go to post

if you are using a routing rule I think you can use the context property Source. So your condition for testing if it came from your "fromLab" busienss service would be 

Source="fromLab"

David Loveluck · Mar 3, 2016 go to post

Without a FIFO requirement, you could simpley increase the pool size on the BO; but if you want to maintain FIFO  for messages referring to the same patient, i don't see a simple alternative to your suggestion.

I have seen solutions that put messages for a patient on a hold-queue until they can be processed, but this seems overkill for your situation. It is complicated to get right.

David Loveluck · Feb 29, 2016 go to post

It looks as if  you are receiving a patient query (QRY_A19) so the approach depends on where the information for the reply is going to come from. 

If the BS has all that information in Ensemble then you can just do as you suggest. If it has to come from a downstream system then you might have to use business service setting 'AckMode=Application'. This means the business service will wait for an ACK  to be sent to it from downstream. If that response is exactly what you want, you can use it. Otherwise you will still have to override OnConstructReply to use the ACK to build exactly what you need.