Hi Mark,

Please read the following doc:

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

From what I understand, you need to create a custom Business Operation that would refer to the Adapter.

ReplyCodeActions only work on a Business Operation. not the Adapter itself. 

You can customize the Adapter if the default version does not do what you need and then refer to the Customized adapter in your Business Operation.

I agree. It looks like you are exchanging message between servers on Port 443, and for this to work, you have SSL Configurations created on each server that communicates with the Hub server (HSREGISTRY). Typically, "Server certificate verification" setting on these configurations should be set to "None". If it is set to "Require" it will likely cause your IIS Server on HSREGISTRY to reject the message.

Alternatively, you may want to check your IIS configuration on HSREGISTRY - does IIS require Client Certificate verification? 

If could be that you do use Certs in between your HealthShare servers, in this case, Aaron is correct and your cert had likely expired. In this case, you will have to replace it on both HSREGISTRY (in your IIS Trust Store Configuration) and on HSBUS (create a file with the new cert and point your SSL Config to that file)

Hi Marcio,

Are you trying to connect to a Cache Web Service from outside application? Or are you using Cache Web Client/Web Service pair to communicate between Cache Servers? 

In general, this error means that your Web Service is not responding. Is it listening on a specific port? Are you trying to connect to that port and is this port not blocked by the Windows Firewall or any other software that may be occupying it?

In addition to these questions, you can activate SOAP Logging on your Server and/or Client machine (I would start with the Server since we already see the error on the Client). You can do this in a Cache Terminal:

YOURNAMESPACE> Set ^ISCSOAP("LogFile") = "C:\temp\SOAP.log" (can be any directory)

YOURNAMESPACE> Set ^ISCSOAP("Log")="ios"

After you try to hit you Web Service, the log file will be created.

When you are done troubleshooting, don't forget to turn off the log:

YOURNAMESPACE> Set ^ISCSOAP("Log")=""

so that your file system would not fill up.

Good luck!

I would strongly advise using Ensemble framework as a starting point as there would be much less coding involved. However, if this is not an option, you probably will need to proceed as follows:

1) Procure a Web Server that can support an AS2 protocol (I assume most Web Servers can do that and you most likely already have one). You would use SSL Certificates to authenticate the request if sent over https, which would be installed into the Trust Store of your Web Server (for Apache on Linux, it is just a file containing nothing but certs that look like hex characters).  I am not familiar with AS2 but I assume that you would probably need to activate a Web Server module for its support and there may be additional certs to install. The incoming requests will be forwarded to your Application Server

(This step is likely needed even if you were to use Ensemble)

2) Build  SOAP-based or REST-based Web Service that can receive http requests with attachments. If you can do all of the authentication on the Web Server, this Web Service will be running on your Application Server. It would simply need to process the request and read your attached EDI file. Here is the docs I found that might be helpful:

For SOAP: https://cedocs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSOAP_intro
For REST: https://cedocs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GREST_services

3) Build business logic to parse the EDI file. This is where Ensemble comes in really handy because it likely already has an EDI parser.

I hope this helps... Maybe someone with more AS2 experience can comment on this thread.

Hi MohanaPriya,

From what I read, AS2 is running on http or https. InterSystems Ensemble provides HTTP InboundAdapter and there is documentation that would help you build a custom Business Service: 

https://cedocs.intersystems.com/latest/csp/docbook/Doc.View.cls?KEY=EHTTP_preface
 

There is also support for EDIFACT documents:

https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=EACT_preface

You many need to customize your business service as I don't think there is direct support for AS2

Hi Jo Ellen,

Can you try to change your SQL query into

INSERT INTO myTable (MessageType) values (?)
SELECT ISNULL(?, '') FROM myTable

I have not tested this but from what I read about ISNULL(), this might work. If your MessageType  field is NULL (I assume that is your default) it should return '' which might parametrize your query...

Hi Alex,

I think when your message is inserted into EnsLib.HL7.Message, it is already parsed... you just need to extract specific data from specific fields.  EnsLib.HL7.Message  class provides lots of methods that you might be able to use. Here is a fairly simple way to do what you need I think:

1) Add a special Business Process type to your Production called "HL7 Router" - you can go to HL7 Router tab in the Business Process Wizard. You can check "Auto-Create Rule" so that it would create your first Routing Rule. You just need to put some name into HL7 Routing Process Name box (it automatically picks the class EnsLib.HL7.MsgRouterRoutingEngine). Your HL7 router will sit between your HL7 Service and HL7 Operation.

2) Create a custom Business Operation (extend Ens.BusinessOperation) and define one method (call it "processHL7Message") that would take EnsLib.HL7.Message object as input. You can now call the following Properties and Methods of EnsLib.HL7.Message:

- Property SeqCount - total number of Segments in the message

- Method GetSegmentAt(segmentCounter).GetValueAt(0): Get the type of the segment (each segment type is in field 0 i.e., MSH, PID, PV1 etc..)

- Method GetSegmentByIndex or GetMutableSegmentByIndex(segmentCounter): Get message Segment object

  Once you get the Segment object you can call GetValueAt(segmentField) - passing in "field.subfield" - for field PID:3.1 you would pass "3.1"

3) Your HL7 Router will have 2 routing rules: the first one will simply pass the message to Enslib.HL7.Operation.TCPOperation. The 2nd rule will pass the message to your custom operation created in step 2:

EnsLib.HL7.Service.TCPService -> HL7Router -> EnsLib.HL7.Operation.TCPOperation

                                                                                            -> Custom Operation (extract fields from message for your business logic)

This discussion assumes that you do not need to change the HL7 message itself, just extract data from it. If you need to also modify the message then you would first need to clone your input Enslib.HL7.Message (so that you have a Response object), do all of the work on the clone and define it as an Output parameter... you can use SetValueAt on the Segment to pass in new field values. your workflow would be:

EnsLib.HL7.Service.TCPService -> HL7Router (orig. message) <-> Custom Operation (extract fields from message and modify them)

                                                                                                                            ->  EnsLib.HL7.Operation.TCPOperation  (modified message)

 I hope this helps

I think I understand better what you are trying to do. You would like to convert a Progress Note being passed in the HL7 v2 message into an XDS.b document. While there may be use cases for this, I just want to mention that Clinical Viewer can display documents stored in the Document streamlet and received via HL7 v2. For example, I would get Discharge Summaries in the MDM message (those were b64-encoded PDF) and they would display in the Documents tab.

Back to your use case:

1. The first step in this process would be to intercept the message somewhere on Edge Gateway where HL7-to-SDA3 conversion is taking place. The issue is, we first need to detect that a document is being stored. If all of your HL7 messages going to that edge carry documents (and you want all of them registered), that step is not needed. I will omit it for the sake of this discussion. So once you determine that there is a Document to be registered, you would need a custom Operation that would create the Register-Document-Set-b metadata and set the correct Repository ID. You will have to create a separate Repository in the OID Registry with an OID as Repository ID and a path to it in the Service Registry (the EndPoint would end on /HS.IHE.XDSb.Repository.Services.cls). The target for this Operation would be XDSb.Registry (HS.IHE.XDSb.Registry.Services on the Hub). You also would need a Document Unique ID and ObjectType (there is a hex value for Stable documents as this would be a Stable, not OnDemand, document)

2. The standard HS.IHE.XDSb.Consumer.Operations is running on HSCONSUMER. You may have to customize it a little bit (see below)

3. I think your workflow is correct. When you customize  HS.IHE.XDSb.Repository.Operations, you will likely use LoadSDA() method and then you can walk to the <Document> SDA, pull the data out and attach it in the Response that the Operation constructs. The HSCONSUMER should process the response (using something like GetDocumentAsSDA()) and create an EPRFetchNotification which will be returned to the Access Gateway.  I think EPRFetchNotification needs to be created similarly to how it is done in HS.Gateway.ECR.Process (which returns regular Edge data)

I think you are on the right path... Good luck!

Hi Paul,

I looked at this and I think your best way is to create a Delivery Detail Filter in HealthShare Delivery Management, then apply it to your Subscription Policy under Subscription Management. Look up the chapter "Subscription Filters" under Unified Care Record Clinical Message Delivery Guide book for details.

In particular, your XPath Context (the root of the tree that the filter operates on) will be "/Container/Diagnoses" and the XPath expression will probably be "count(Diagnosis)>1 and Diagnosis/EnteredOn=following::Diagnosis/EnteredOn" (I had not tested this...) This is a bit crude... from the look of it, it will only flag those that have exact timestamp... you may need to process the XML timestamp a bit as in "substring-before(EnteredOn,'T')" - you would replace EnteredOn with this expression - that should chop off the timestamp. 

After you create this Detail Filter, you should be able to see it in the Detail Filters tab on your Subscription Policy for your Source/Event Type/ Information Type/etc... Subscription Basis.

I hope this helps somewhat...

Good luck!