Hi

What are your settings for charset, content type and content encoding?

I would expect to see something like this:

  1. ContentEncoding = "HL7-ER7"
  2. ContentCharset = "UTF-8"
  3. ContentType = "application/hl7-v2"

The most common type of framing is MLLP. If you are acting as an HL7 server tand you don't know what the client framin is then set framing to flexible. that way ensemble will try and detect the framing based on the properties listed above and by looking for tell tale characters (segment terminators) such as LF $c(10) or CR,LF $c(13,10).  Depending on the properties listed above you may see the terminator represented as "/r". 

If you are the HL7 client then you can get away with framing = none provided both you and the 3rd party server are consistent on the content type, charset and encoding.

I hope that gives you some ideas of what to look out for and the questions you need to ask the 3rd party application you are trying to communicate with.

Yours

Nigel

Hi

I am wondering if this is a user security level issue. As you know you need Windows/Unix Administrator rights to install Cache/Ensemble/IRIS. The same is true if you want to run any of the executables in the 'bin' directory such as cstart cachesystray and so on. I am not a UNIX expert and so I can  only speak from my Windows experience but assuming this is windows close the Cache/Ensemble/IRIS systeray icon and then from the 'bin' directory fine th csystray.exe, right click and slect 'run as administrator', then see if you can start or shut down your instance.

If that fails and all other suggestions from the Developer community uninstall C/E/IRIS and reinstall it making sure you run the installation as 'Administrator'

The final suggection is check your cache.key or iris.key and make sure your license is still valid.

Yours

Nigel

Hi

Can you upload the class definition of the table that contains the data as well as the routines that were generated by the sql compiler i.e. the classes and routines for *.SMTKTUAT.*.* (.cls, *.int)

Have you tried accessing the data through the Management Portal->Stystem Explorer->SQL->Execute Query?

Have you tried setting up an ODBC DSN and then accessing the table from within say Excel?

If you set up a Windows ODBC DSN you can turn on logging for the DSN

To resolve this issue you need to isolate whether the issue lies within the code generated by IRIS for the sql statement, or whether it is the ODBC/JDBC connection functionality.

Have you written a simple class method using %Library.ResultSet as in

classmethod TestQuery() as %Status

{

      set tSC=$$$OK

      try {

              set rs=##class(%ResultSet)).%New("%DynamicQuery:SQL")

              set tSC=rs.Prepare("select col1, col2, ...., colN from Table where ....") if 'tSC quit

             set tSC=rs.Execute() if 'tSC quit

             while rs.Next(.tSC) {

                     if 'tSC quit

                     write !,rs.Data("Col1")," ",rs.Data("Col2")," ", ...., rs.Data("ColN")

           }

         }

         catch ex {set tSC=ex.AsStatus()}

        if 'tSC write !,$system.Status.GetErrorText(tsc)

        quit tSC

}

Nigel

Hi

Bear in mind that when you are working with DTL's when you invoke the Transform() method there is a third parameter called aux. The aux object can be an instance of any class you design and can contain any properties you desire. These are typically values that you want to use in the DTL that are not part of your request object.

When you call the DTL you create a new instance of your aux class and then when you invoke the DTL Transform you can write the following code:

set tSC=##class({Your DTL}).Transform(request,.response, .aux) where aux is an instance of your custom aux class.

This is true also of DTL's called from a BPL with one exception. If the DTL is invoked from a Business Rule then the Business rule creates an instance of a system defined aux object that contains information about which rule invoked the DTL and so on. 

I am busy trying to convert a Custom Code Business Process that will invoke a DTL and am still trying to get my head around what variables/objects are available in the BPL (Context) and the DTL.

If you resolve how to create a BPL using the context object and then invoke a DTL into which you can pass data other than the request and response message I would be interested to know how if you have success and how you managed to get it to work.

Yours

Nigel

Hi

Here is an example of a HTTP Operation POSTing HL7 messages. this HTTP request uses HTTPS and a Proxy Server. The lines I have highlighted in Yellow will be different in your case as you are sending JSON. Not clear if you are using FHIR. However your ContentType will most likely be application/json or application/json+fhir

    set tSC=$$$OK,pResponse=""
    try {
        set message=pRequest.OutputToString(,,.tSC) if 'tSC quit
        set tResponse = ##class(%Net.HttpResponse).%New(),tResponse.ContentType="application/hl7-v2"
        if '$IsObject(..HTTPRequest) {
            set pHttpRequest=##class(%Net.HttpRequest).%New()
            set pHttpRequest.Server=..Adapter.HTTPServer
            set pHttpRequest.Port=..Adapter.HTTPPort
            set pHttpRequest.ProxyServer=..Adapter.ProxyServer
            set pHttpRequest.ProxyPort=..Adapter.ProxyPort
            set pHttpRequest.ProxyTunnel=..Adapter.ProxyHttpTunnel
            set pHttpRequest.ProxyHTTPS=1
            set pHttpRequest.SSLConfiguration=..Adapter.SSLConfig
            set pHttpRequest.UserAgent="curl/7.29.0"
            set pHttpRequest.ContentEncoding="HL7-ER7"
            set pHttpRequest.ContentCharset="UTF-8"
            set pHttpRequest.ContentType="application/hl7-v2"
            set pHttpRequest.AcceptGzip=0
            set pHttpRequest.WriteRawMode=0
            set pHttpRequest.ReadRawMode=0
            set pHttpRequest.OpenTimeout=..Adapter.ConnectTimeout
            set pHttpRequest.Timeout=..Adapter.ResponseTimeout
            set pHttpRequest.WriteTimeout=..Adapter.WriteTimeout
            set pHttpRequest.SocketTimeout=115
            set ..HTTPRequest=pHttpRequest
        }
        set ..HTTPRequest.HttpResponse=tResponse
        do ..HTTPRequest.EntityBody.Write(message)
        set tSC=..HTTPRequest.Post(..Adapter.URL,0,1) if 'tSC {
            set sc=$$$DebugLog("HTTP Write","Error: "_$$$GetErrorText(tSC))
        }
        else {do $$$DebugLog("HTTP Write","Post Sucessful)}
        set response=..HTTPRequest.HttpResponse
        $$$TRACE("HTTP Response Status: "_response.StatusCode)
        if response.StatusCode=200 {
            if $IsObject(response.Data) {
                set message="" while 'response.Data.AtEnd {set message=message_response.Data.Read(,.tSC) if 'tSC quit}
                set pResponse=##class(EnsLib.HL7.Message).ImportFromString(message,.tSC) if 'tSC $$$TRACE("An error occurred creating Respnse Message: "_$system.Status.GetErrorText(tSC))
            }
        }
        else {
            set message="" if $IsObject(response.Data) {set message="" while 'response.Data.AtEnd {set message=message_response.Data.Read(,.tSC) if 'tSC quit}}
            set tSC=$$$ERROR(5001,"HTTP Response Status is "_response.StatusCode_" with Error Text: "_response.ReasonPhrase_" with Content: "_message) quit
        }
    }
    catch ex {
        set tSC=ex.AsStatus()
    }
    if 'tSC,'$IsObject(pResponse) {

  // Here I create a NACK HL7 message if I didn't get a valid response from the remote server. Possibly because the server is down or the 

 //server has crashed. I have a DTL that takes the inbound HL7 request message and transforms it into an HL7 ACK message. I force the ACK 

// Code to "AE" and use the contents of tSC (error status) as the Error Message. Note I make use of the 3rd parameter in the Transform()

// method that allows you to pass in an object containing any properties you want. This is a useful way of getting data into the DTL that

// doesn't exist in either your sourse or target objects.

        set pResponse=##class(EnsLib.HL7.Message).%New(),aux=##class(HPRS.Transformations.CreateNACKDTL.AUX).%New()
        set aux.ACKCode="AE",aux.ACKMessage=$system.Status.GetErrorText(tSC)
        set sc=##class(HPRS.Transformations.CreateNACKDTL).Transform(pRequest,.pResponse,.aux) if 'sc $$$TRACE("Unable to Create NACK Response HL7 Message")
    }
    $$$TRACE("Outcome of HTTP Operation: "_$s(tSC:"Ok",1:"Error: "_$$$GetErrorText(tSC)))
    quit $$$OK

Yours

Nigel Salm
 

Hi

The short answer is yes, you are constrained by the 3.6Mb string size limit and bear in mind that if you are exposing that property to SQL and ODBC you are further constrained by the limitations within ODBC itself. 

I have been giving this whole concept a lot of thought recently. My context is slightly different as I am working in the context of FHIR and JSON and for example you can send in a patient's photo which in JSON has to be represented as a string of Base64Encoded Binary . In principal that photo could be of any size but when the JSON string is converted into a FHIR Patient Object the underlying datatype of the photo.data.value is ultimately derived from a class called %xsd.Base64Binary which is esentially a string and therefore has the size limitation. It doesn't really matter what my underlying persisted datatype is i.e. %GlobalBinaryStream because I am working with the IRIS FHIR Classes as intemediary object classes between my JSON and my underlying persisted classes I have to work with the constraint that the JSON Base64Binary content will fail if it's length exceeds the 3.6Mb (something I wish to address with ISC/WRC at some point).

The alternative of course, to persisting larger data content of something link an image, is to have a url that points to the image location and can be retrieved from the image server for presentation purposes.

So where I know that my images are not going to be that large I read in or write out the base64binary from/to my JSON message but where I know the image is larger such as an x-ray or histo image then that content lives on the appropriate image server as is retirieved  when required for presentation purposes.

Nigel Salm

Hi

Remember that not only messages contribute to the volume of ensemble generated data. If you are using $$$TRACE in your production then this will generate a lot of data in the Ensemble namespace . If you have lots of TRACE statements then this can generate a lot of data.

There is a class method

do ##class(Ens.Purge).PurgeEventLogsByDate({NumberOfDaysToRetainTraceData},.count) There are other methods in this class to purge other management data such as messages

Trace information is stored in the global  ^Ens.Util.LogD and  ^Ens.Util.LogI

Nige;

My guess is that you need to specify Exception as a Status i.e.:

Exceptuion.AsStatus()

and then your code should read

set pOutput=##class(MyResponse).%New()

set sc=Exception.AsStatus()

set pOutput.errorString=$system.GetErrorText(sc)

but another thought:

If your method quits with tSC (as a %Status) then presumably your method quits with

quit tSC

in which case instead of trowing tSC just quit your Try {} with quit tSC

and in your catch write it as follows:

catch Exception {

   set tSC=Exception .As Status()

}

set pOutput=##class(MyResponse).%New()

set pOutput.errorString=$s(tSC:"",1:$system.Status.GetErrorText(tSC))

quit tSC

Hi

I certainly concur that you do not want to go changing names in any InterSystems Library or System Classes. To be quite honest in my experience export the classes or project that contain all of the classes you want to manipulate and then open that XML export file in NotePad ++ .

Bear in mind that classnames, property names, method names, and storage definitions will all be modified and you should be certain that that is acceptable and desirable otherwise you will need to go through the painful task of working your way through the XML file instance by instance and confirm each replace.

Also bear in mind that if your Class Export references other IRIS classes other than your own application classes then you need to be careful that you don't change an IRIS classname/property name etc... as you may well find that your system no longer works.

Having done the search and replace I suggest that you create a blank database/namespace and import the modified xml file and check any error messages thrown up  by the import process before attempting to import into your proper DEV/UAT database/namespace(s)

Nigel

Hi

Follow this link to the InterSystems Documentation. It details many utilities that can be run from the Cache Terminal. Those that start with a '%' character can be run from any NameSpace. Those without will typically only run in the %SYS NameSpace

https://cedocs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSTU
 

Bear in mind that many command line utilities have been encapsulated in the  %SYS, %SYSTEM,  %SQL, %Dictionary and other system Packages.

Most of the functionality of the Management Portal is linked to underlying classes and most of them have Methods that can be called programmatically; for example creating resources, roles and users in the security module. Most database and Namespace functionality can be accessed through the %SYS and %SYSTEM packages

If you are looking for specific functions that you would like (if they exist) please list them and I'll see if I can point you in the right direction

Yours

Nigel Salm

Here is a solution I have knocked up that uses the functionality of the Ensemble File Adapter and the HL7 File Operation class

Class User.ExampleHL7FileOperation Extends (Ens.BusinessOperation, EnsLib.HL7.Operation.FileOperation) [ Language = objectscript ]
{ Parameter ADAPTER = "EnsLib.File.OutboundAdapter"; Property Adapter As EnsLib.File.OutboundAdapter; Parameter INVOCATION = "Queue"; Method WriteMessage(pRequest As EnsLib.HL7.Message, Output pResponse As EnsLib.HL7.Message) As %Status
{
        // Initialise your return status variable and a variable called file
        // I use $ztrap to trap code errors though TRY/CATCH would be the more modern approach
        set tSC=$$$OK,$ztrap="Error",file=""
        // Create your file name and append to the Adapter Attribute 'FilePath'
        // if working with UNIX change the next line of code accordingly
        if $e(..Adapter.FlePath,*)'="\" set ..Adapter.FilePath=..Adapter.FilePath_"\"
        set file=..Adapter.FilePath_"ZLOG_FILE_"_pRequest.GetValueAt("MSH::MessageType.MessageStructure",,tSC)_$tr($zdt($h,3),"-: ","")_".txt" if 'tSC quit tSC
        // You can use the appropriate method in the File Outbound Adapter though I have used the OPEN
        // command
        open file:("WNS"):0
        else  set tSC=$system.Status.Error(5001,"Cannot create File: "_file) goto End
        // Invoke the outputDocument method inherited from the class 'EnsLib.HL7.Operation.FileOperation'
        set tSC=..outputDocument(file,pRequest) if 'tSC goto End
End ;
        // Close the file if it exists
        if file'="" close file
        set pResponse=##class(EnsLib.HL7.Message).%New()
        // Populate the response HL7 message as you see fit. Either send back an HL7 ACK or NACK would be
        // the most appropriate
        quit tSC
Error ;
        set $ztrap="",tSC=$system.Status.Error($$$GeneralError,"Code Error: "_$ze) goto End
} XData MessageMap
        {
        <MapItems>
                 <MapItem MessageType="EnsLib.HL7.Message">
                        <Method>WriteMessage</Method>
                </MapItem>
        </MapItems>
        }

}

I have not trested the code but hopefully my coments will set you on the right path to this solution

Many of the terminal based utilities use '^' <enter> to return to the previous field.  In older versions of the Cache utilities  it really depends on who the developer was who wrote the program as well as which area of the product the program was writtren for. There isn't necessarily consistancy between the developers or functionality of the programs.

Most interactive utilities are now accessed through the %SYSTEM package which is accessed using the notation $system....

e.g. set status=$system.Status.Error(5001,"This is a general Error")

Various configuration items can be accessed through this package and the classes therein.

Another package worth noting is %Dictionary that gives you access to all aspects of class definitions, methods, properties, compiled classes etc...

and finally the package %SYS contains may more system related classes

The only other comment is that many system functions require you to be in the %SYS namespace in order to execute the function you require and will also require that you have sufficient roles assigned to your user account to perform such actions.

You can't use $get or $data on an object property. What you should do is as follows,

If $IsObject(ref) {set ^AK(1)=ref.Title}

Else {set ^AK(1)=""} // or whatever you want to do if ref is not an object

You could also do this:

If $IsObject(ref),$l(ref.Title) {set ^AK(1)=ref.Title}

Else {set ^AK(1)=""} // or whatever you want to do if ref is not an object or ref is an object but the property title is null

Hi

 

WRC helped answer this:

 

Here is the code to build into your TablePane form:

 

ClientMethod onloadHandler() [ Language = javascript ]
{
zenPage.IntervalRefresh();
myVar1 setInterval(zenPage.IntervalRefresh,1000);
}

ClientMethod IntervalRefresh() [ Language = javascript ]
{

var table zenPage.getComponentById('TableName');
//Optional if Snapshot is used
table.executeQuery()
table.refreshContents()
}

Note that the line table.executeQuery() is only required if your TablePane uses snapshot mode

 

Nigel

If you specifically wanted to make use of the Sample Classes in an Ensemble context then I would suggest one of two approches:

1) Export the Sample Classes and Data and import them into the ENSDEMO namespace though bear in mind that were you to reinstall Ensemble the ENSDEMO database might be replaced

2) The better approach would be to create a new database/namespace which will automatically inherit the Ensembele mappings and then import the SAMPLES classes and data into that new namespace/database