Thanks John,

I thought about that but it fails- even if I copy/paste the class path reference '##class(LNWDeploy.RoutingRules.Utility).' from the successful compile:

set tTempVars("SendToEaling")=##class(LNWDeploy.RoutingRules.Utility).SendToEaling((pContext.HL7))

error text

Compilation started on 09/06/2018 14:43:45 with qualifiers 'cuk /checkuptodate=expandedonly'
Compiling class LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP
ERROR <Ens>ErrParsingExpression: Error parsing expression '##class(LNWDeploy.RoutingRules.Utility).SendToEaling(HL7)': ERROR <Ens>ErrInvalidName: Invalid name at offset 1
  > ERROR #5490: Error running generator for method 'evaluateRuleDefinition:LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP'
ERROR: Ens.Rule.Definition.cls(evaluateRuleDefinition) of generated code compiling subclass 'LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP'
    > ERROR #5030: An error occurred while compiling class 'LNWTIEPackage.iCSADTHL7MainRouterRoutingRuleDUP'
Detected 1 errors during compilation in 0.086s.)

Is my only option is to delete LNWDeploy.RoutingRules.Utility and recompile?  

(it would be nice to be able to specifiy the full class path - but if routing rules don't support it I don't want to keep 'banging my head against a brick wall')

Thanks again

Stephen

The documentation provides a method to specify the full class path for DTL's,

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

e.g.

##class(HP.Util.funciones).normalizaSexo(source.{Sex})

While it does note the syntax for calling utility functions is different for routing rules (the '..' prefix is not required), I can't see the correct full class path syntax in the documentation.

Any help appreciated.

Stephen

Suriya at WRC solved this for me

Where I went wrong: 

  1. I created context.pidSegment as EnsLib.HL7.Segment - which fails as an argument to the DTL <assign> statement)
  2. I forgot the (1) in {PIDgrp(1).PID}

The right way to copy a segment from one message to another is;

  1. create context variable as a string:  e.g. context.pidSegment as %String(MAXLEN=2500) 
  2. extract the segment as a string: context.k22.GetValueAt("PIDgrp(1).PID")
  3. use the DTL to set the right field: <assign value='context.pidSegment' property='target.{PIDgrp(1).PID}' action='set' />

Thanks go to Suriya at WRC

Stephen

Hi,

  1. On your inbound FHIR Patient Query message, first try to see if the PDQm Services can successfully transform it into a HS.Message.Patient Search Request.

Using the HealthShare Test Utility, PIX and PDQ (FHIR), Patient Search (PDQm), with the supplier set to 'PDQm.Supplier' I did a simple search, but got a 'No production is running' error.

have I missed something in setting up PDQm?  It looks like I need to have a HSREGISTRY namespace/production/web application  running at /csp/healthshare/hsregistry/services/HS.Hub.HSWS.WebServices.cls  ? 

Is that right?


'No production is running' error: 

HTTP Status = 500 Internal Server Error
ERROR #5001: ERROR #6248: SOAP response is a SOAP fault: faultcode=Server faultstring=Server Application Error faultactor=HS.Hub.HSWS.WebServices detail= <error xmlns="http://www.intersystems.com/hs/hub/hsws"> <text>ERROR &lt;Ens&gt;ErrProductionNotRunning: No production is running</text> </error>

[2018-04-19 17:15:55] Service:nn-tie2v:57772

HS.Test.UI.PDQm Run: 2018-04-19 17:15:55 Test Id: 7

PS I added PDQm to the production as per the instructions in HealthShare Health Connect  >  IHE Use Cases in Health Connect  >  Using FHIR® IHE Profiles  >  Setting Up and Using PDQm 

do ##class(HS.Util.Installer.Kit.FHIR.ServerPDQm).Add(, "namespace")

I had created the FHIR production/namespace earlier:

do ##class(HS.Util.Installer).InstallFHIRServer("namespace")

Thanks for responding. My apologies for the delayed response.

does not conform to FHIR's RESTful Search specification;
it appears to be a custom REST call

you are right!

it sounds like you are seeking to implement a message transformation interface
that enables a PDQ (Patient Demographics Query)-type transaction.

yes.

I think you should take a look at our existing support for IHE PDQ (v2) and PDQm (FHIR-based) profiles

Can you provide a link?

If the client system could be made to conform to the FHIR RESTful Search standard,
then it may be easier to make direct use of our existing PDQm capabilities.

Can you provide a link?

Thank you for taking the time to respond.

Stephen

(formatting corrected)

Hi,

My apologies for the delay getting back to you.

Is the QBP^Q21 actually an IHE PIX or PDQ query request or just a plain HL7 V2 QBP^Q21?

it is just a ' just a plain HL7 V2 QBP^Q21'

What is the workflow?

  1. Client system sends a FHIR PDQ using a patient identifier.
  2. Healthshare FHIR server web application receives from the client system
  3. FHIR PDQ converted to HL7v2 Q21 ans sent to PAS
  4. PAS responds with patient demographics (or fails)
  5. response converted to FHIR response
  6. FHIR response containing patient demographics sent to client system in FHIR response.

What is the triggering event for this workflow?

A user searching for a patient in the client system. (standard clinical workflow app)

You don't have to use SDA as an intermediary to translate HL7 V2 FHIR. You can also do this directly using DTL

Can you provide more details about how this should work?

If the QBP is being sent to you instead of being sent by you

No, we are making the QBP^Q21 HL7v2.4 message to the PAS as it is the only way to query our PAS in real time.

Thanks again for taking the time to respond.

Stephen

Thanks for responding. My apologies for the delayed response. >does not conform to FHIR's RESTful Search specification; > it appears to be a custom REST call you are right! >it sounds like you are seeking to implement a message transformation interface >that enables a PDQ (Patient Demographics Query)-type transaction. yes. > I think you should take a look at our existing support for IHE PDQ (v2) and PDQm (FHIR-based) profiles Can you provide a link? >If the client system could be made to conform to the FHIR RESTful Search standard, > then it may be easier to make direct use of our existing PDQm capabilities. Can you provide a link? Thank you for taking the time to respond. Stephen

Thanks

good point about SHA1 

- this is brilliant:

I:\Projects\certiificates>openssl x509 -text -in certsForStunnel.pem -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            af:0c:7a:b9:44:11:6c:e8
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C = GB, ST = West Somewhere, L = Town, O = XXX, OU = HL7, CN = VENDOR HL7 Messaging API
        Validity
            Not Before: Apr 13 10:48:24 2017 GMT
            Not After : Apr  7 10:48:24 2042 GMT
        Subject: C = UK, ST = London, L = London, O = LNWH NHS Trust, CN = TIE
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:e0:24:df:16:3d:d4:ed:1f:b0:4a:2b:6a:07:a7:

[truncated]

Thanks for the clarification, I think I was a bit confused.  I was working from an existing SOP which may be wrong, but as it is based on the assumption that we don't have a CA. (Our organisation is the client sending messages to the vendors server)

The SOP (summarised) is:

  1. Client generates private key(a) and certificate request(b)
    (openssl req -new -keyout privatekey.pem -out request.crs -days 9125 -newkey rsa:2048 -sha1  [2])
  2. the certificate request(b) is sent (securely) to vendor
  3. the vendor signs the certificate request and and returns both the client certificate(c) and their ceritficate(d)
  4. we create a SSL/TLS configuration that our service will use to connect to the vendors server: we populate the following fields: 
    1. trusted Certificate Authority X.509 certificate(d) - supplied from the vendor
    2. client certificate(c) - returned by the vendor after we sent our certificate request
    3. client private key(a) we created initially.

In this case I think the vendor is acting as the CA by signing our certificate request. (I've tried inspecting the certificate they provided but I'm not sure how to tell if it is self-signed, or signed by one of the big CA's)

I think this is fine for testing, and maybe while we have a small number of interfaces, but in the longer term I believe we need to manage this properly: use the cache Certificate Authority server, and 'Caché Credential Sets'.

 

---

[1]simplified summary of Mutual Authentication from https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication 

1.A client requests access to a protected resource.
2.The server presents its certificate to the client.
3.The client verifies the server’s certificate.
4.If successful, the client sends its certificate to the server.
5.The server verifies the client’s credentials.
6.If successful, the server grants access to the protected resource requested by the client.

---

[2]  we know we shouldn't use sha1 but are limited to what the vendor supports.
 

Hi, 

wrc just confirmed that externally created certificates can't be signed using the IPKI

If you need to sign a certificate request to create a client certificate, you can use openssl:

 openssl x509 -req -days 365 -in [client]request.crs –signkey YOUR-CAprivatekey.pem -out [client].cer

This uses your private key to sign their certificate request to create their client certificate.

 You should send your CA certificate (not the private key) and the signed client certificate back to the client.