Marc Mundt · May 16, 2018 go to post

I'd suggest contacting the WRC to help look at the problem you're seeing with unwanted characters in the output. EnsLib.RecordMap.Operation.BatchFileOperation does what you've described, so it would be best to get this working for your use case if possible.

Looking at the code you posted...

pRequest.Records.GetAt(1)

This will just get you the first record from the batch. If you want to get a specific field from a record you would want to use something like:

pRequest.Records.GetAt(1).FieldName
Marc Mundt · May 2, 2018 go to post

One thing I see is that you don't need a value for the "key" attribute in the assign for callrequest.EOBList.  Key is used to assign the value to a specific member of an array/list whereas it looks like you want to assign the entire list.
Does this work better?
<
assign property="callrequest.EOBListvalue="context.tEOBListaction="set" key="/>

Are StageBatchId and Filename getting passed correctly?

Marc Mundt · Apr 20, 2018 go to post

When you mention HL7 adapters, I assume you mean the IO log entry that Ensemble stores if you have "Archive IO" enabled for the HL7 operation?

If you want to do something similar for your custom operation, have a look at the *IOLogEntry methods in Ens.BusinessOperation.

Marc Mundt · Apr 10, 2018 go to post

It sounds like you're running on Windows?

Check Task Manager to see what user your "cache.exe" processes are running as. This user needs to have the appropriate permissions for \\share\folder\.

Some more information

Marc Mundt · Apr 10, 2018 go to post

I just read Dave Loveluck's suggestion below and that sounds like a much better option.

Marc Mundt · Apr 9, 2018 go to post

Archunan,

Can you give some more details about your use case? I'm having trouble picturing what the downstream system should receive.

Should the receiving system just receive a single message that combines the HL7 and flat records together like this?

MSH|^~\&||HC6|||||MDM^T02|||2.5
EVN|T02|20180117094500
PID|||LD572046^^^HC6^MR||Smith^John||19301019|M|||1 Memorial Drive^^Cambridge^MA^02142||||||||063070516
PV1||O|||||ISCGP001^Moore^James|||||||EO|||||HSVN00006|||||||||||||||||||||||||20180117094500|20180117094500
TXA||Progress note||201801170945|JJ021^James^John||||ISCGP001^Moore^James|||19815952^TRANS
OBX||FT|RTF^TRANS||Patient complaining of pain in right big toe. Toe red in colour. To commence on antibiotics.||||||R
FlatFileRow1Field1,FlatFileRow1Field2,FlatFileRow1Field3
FlatFileRow2Field1,FlatFileRow2Field2,FlatFileRow2Field3
FlatFileRow3Field1,FlatFileRow3Field2,FlatFileRow3Field3
Marc Mundt · Apr 7, 2018 go to post

Mike, can you post a sample of the code you're using and/or details about the utility?

Marc Mundt · Feb 9, 2018 go to post

Thanks Lorraine.

At this point it would be best to open a WRC ticket so a support rep can help look into this in more detail.

Marc Mundt · Feb 8, 2018 go to post

Thanks, this is helpful.

In your routing rule, can you try setting the condition from "Document.OriginalFilename Contains "NTWD33"" to "1"?  Also, can you post a snapshot of the "general" tab in the rule editor?

Marc Mundt · Feb 8, 2018 go to post

Hi Lorraine,

A few questions to help us get a clearer picture:

  • Which component is generating the 5005 error? Is it the router or the business operation?
  • Can you post a screenshot or the source code for your routing rule?
  • Is your router calling a transformation or just passing the file through unchanged?
  • What happens if you remove all logic from your router and just change it to do a simple "send" with no transformation?

-Marc

Marc Mundt · Jan 11, 2018 go to post
what would be the best way to block user access to certain portions of the website or entire pages?

In Caché/CSP terms, you would define a custom resource that represents the pages/sections that require different privileges, then assign access to that resource to a role, and assign that role to any users that should be allowed access.  In your CSP page you would then check if the current user has the necessary privileges and act accordingly.

This short tutorial gives a more detailed overview:
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=TSQS_Authorization

Marc Mundt · Jan 11, 2018 go to post

It sounds like you might be able to avoid the problem of converting to XML and creating an EnsLib.EDI.XML.Document if you were able to access fields in your persistent message class from your routing rule logic?

If your persistent message class has discrete properties, you can still refer to these directly in a routing rule condition even without the VDoc style GetValueAt().

If your message object has references to repeating child objects and you need to get to a deeper level such as checking a property of the Nth child object you can do this by creating a custom function and passing it the Document object as a parameter.

Marc Mundt · Jan 8, 2018 go to post

Does it need to be a binary executable or would a batch file work? It is possible to execute a Caché routine/method from a Windows command line or batch file by invoking the Caché binary and passing it the name of what you want to execute.

The docs give this example for freezing and thawing the database for backups:
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…
 

CD C:\InterSystems\E20131\mgr\
..\bin\cache -s. -B -V -U%SYS ##Class(Backup.General).ExternalThaw()
Marc Mundt · Dec 5, 2017 go to post

The high-level steps are:

  1. Create a Java class using the APIs provided by your JMS server (ActiveMQ, RabbitMQ, etc.) and create a JAR file. JMS is a standardized API, not a protocol, so there is not one universal JMS client that will work with all JMS servers.
  2. Use the Java Gateway wizard to generate COS proxy classes for your Java class
  3. Setup a Java Gateway Service in your production. Make sure it points to your custom JAR file and the JAR file provided by the JMS server vendor.
  4. Create a custom business service or operation that calls the COS proxy class methods.
  5. When adding the service or operation to the production, configure it to point to the Java Gateway Service and use the correct Java class

For a Business Operation, you'll just use the usual approach: the message map points to a custom method. The custom method then calls the COS proxy class methods for your Java class. The BO class should extend Ens.BusinessOperation and use the adapter EnsLib.JavaGateway.OutboundAdapter.

For a Business Service, there's an out of the box adapter, EnsLib.JavaGateway.InboundAdapter. You just need to create a custom Operation that extends Ens.Business service and uses EnsLib.JavaGateway.InboundAdapter as it's adapter. This is quite nice, because EnsLib.JavaGateway.InboundAdapter handles most everything automatically. Your Java class just needs to implement a set of methods defined by the Inbound Adapter. See the class reference for EnsLib.JavaGateway.InboundAdapter for more details:
 *             .Connect(pJGClientConnectSpec,pTimeout,pInbound)
 *             .Disconnect(pInbound)
 *             .IsConnected(pInbound)
 *             .getErrorText() [returns empty string if no error on previous method call]
 *             .ReceiveMessage(pTimeout) [inbound only; pMsgIn return needs not be populated if timed out]
 *             .SendResponse(pMsgOut) [inbound only, optional-needed if OnProcessInput will return an object]
 *             .SendMessage(pMsgOut,pGetReply,pResponseTimeout) [outbound only; pMsgIn return needs not be populated if no responses are anticipated]

I've created some sample code including a production and Java classes. It includes a generic class that implements most of the necessary methods using standard JMS API methods and provides an ActiveMQ-specific subclass that uses the ActiveMQ proprietary methods to initiate the connection.

As always, this is sample code for demonstration purposes only and is not production ready.

Marc Mundt · Dec 1, 2017 go to post

Alerts (Ens.AlertRequest) are treated like any other message in Ensemble -- you can transform them to different message types and route them to an outbound business operation.

Have a look at the docs regarding alerts here:
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…
And the docs regarding file adapters here:
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

One approach you can consider is to transform the Ens.AlertRequest into an Ens.StreamContainer and then use an EnsLib.File.PassthroughOperation to write it out to a file:
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

If you need to write the alert to a file in a structured format, you can consider creating a RecordMap for your output format, transform the Ens.AlertRequest into your custom RecordMap object, and then use EnsLib.RecordMap.Operation.FileOperation to write it out to the file:
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

Marc Mundt · Nov 29, 2017 go to post

I know it's at least used to filter the list of target components when you create a "send" action. I'm not sure where else it applies.

Marc Mundt · Nov 29, 2017 go to post

One approach would be to create a custom business service that manages an SSH connection by calling a command line SSH client similar to your existing UNIX scripts. It would start the connection when the production/business service starts, clean it up when the service is stopped, and can log errors in the Ensemble error log.

Marc Mundt · Nov 23, 2017 go to post

You can use ^JOBEXAM in terminal or the process details page in the System Management Portal to see the current state of the job. This gives you access to the process's current variables which should include the current row ID being purged.

Marc Mundt · Nov 22, 2017 go to post

Gertjan, can you add your solution to this topic as a new "Answer"?
Thanks,
Marc

Marc Mundt · Nov 20, 2017 go to post

You can use the Enumerate stored procedure in the Ens.Job class to get a list of running Ensemble jobs (config items) in the current namespace. If you need to get other system level details about the process, the "job" field is the same as the process id from %SYS.ProcessQuery.
From a SQL query tool you can call it with:
call Ens.Job_Enumerate()
From my earlier comment: %syPidtab.inc includes a list of Job Types and their corresponding IDs.

Marc Mundt · Nov 20, 2017 go to post

 %syPidtab.inc includes a list of Job Types and their corresponding IDs.

By "configname", are you referring to Ensemble production items or something else?

Marc Mundt · Nov 16, 2017 go to post

Hi Joe,

I assume that CreateTextMessage is being called from a custom Business Operation similar to what's outlined in this chapter.

If you are passing an HL7 message to the Business Operation, and your operation's message map looks like this:

XData MessageMap
{
<MapItems>
  <MapItem MessageType="EnsLib.HL7.Message">
    <Method>SendEmail</Method>
  </MapItem>
  ...
</MapItems>
}

...then your SendEmail method can use the GetValueAt() method of the EnsLib.HL7.Message object to retrieve a field value using the same syntax that you use in DTL. Have a look at the docs for EnsLib.HL7.Message and specifically GetValueAt.

It would look something like this:

Method SendEmail(myMessage As EnsLib.HL7.Message, Output pResp As ResponseClass) As %Status {
    set myEmail=myMessage.GetValueAt("PID:13(1).4")
    set msg=..CreateTextMessage(myEmail)
    ...
Marc Mundt · Nov 15, 2017 go to post

Here's a quick example that returns a custom HL7 message back to the upstream system instead of a standard ACK.

Example

Marc Mundt · Nov 15, 2017 go to post

Jess,

I see that it's been a month since you posted this, so you've probably found a solution already.

Application ACK mode should still be what you want to use. It doesn't matter if you're actually sending it to another application -- your Business Process can return the RSP_K22 to the Business Service and it should send it back to the caller.

Marc

Marc Mundt · Nov 15, 2017 go to post

Here's a sample for creating a proxy object and outputting it as JSON:

Set tProxy = ##class(%ZEN.proxyObject).%New()
Set tProxy.Property1 = "Some value 1"
Set tProxy.Property2 = "Some value 2"
Set tSC=##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(.tStream,.tProxy)
Write "Result (blank means no error):",$System.Status.GetErrorText(tSC),!
Write "JSON output:",!
Do tStream.OutputToDevice()

This produces the following output:

Result (blank means no error):
JSON output:
{
        "Property1":"Some value 1",
        "Property2":"Some value 2"
}
Marc Mundt · Nov 14, 2017 go to post

%ZEN.Auxiliary.jsonProvider can make use of %ZEN.proxyObject to represent the JSON. This wouldn't require a formal class definition for your objects.