Thursday, October 10, 2019

Upgrading HAPI on FHIR (part 2)

"
I'm still in the process of upgrading FHIR Microservices that have been developed using HAPI on FHIR 3.6 to HAPI on FHIR 4.0.  Earlier this week I shared my initial experiences, here's a few more.

Most of the subsequent challenges I've had are related to upgrading from Spring 1.5.6 to 2.1.1 and consequent changes updating my tracing libraries.

But I've found two tricky issues related to other components, one related to HL7 R4 classes and the Validator, and another related to uses of Embedded MongoDB for some of my testing.

Too many QNames

The first issue relates to uses of the XPP3 libraries that Grahame likes to use for efficient XML parsing.  The challenge here is that XPP3 is ancient and not being actively maintained.  Soooooo...
it exists before Oracle added javax.xml.namespace.QName to the Java Runtime library, and as a result, XPP3 rolled their own (actually, they copied it from an Apache Axis implementation) to support parsing.

The key problem for this is that the javax.xml.namespace is already defined in the JRE in a modular fashion, and so cannot be defined on the classpath when using a JRE after Java 8.  I'm using OpenJDK 11, so I'm affected.
I had a workaround which meant that I never really noticed this, because prior to Eclipse release 2019-06, you could have your JRE on your classpath, and it wouldn't cause a problem, but if you placed it in your imports modularly, then it would.

Having recently upgraded my Eclipse release to 2019-06, which no longer allows you switch the JRE libraries from the modules to classpath entries, I cannot work around the issue in local Eclipse builds.

The simple solution seems to be to strip the javax.xml.namespace.QName class from my downloaded XPP3 (1.1.4c) jar file, and use that instead of the usual one.  I'll probably rename it, put it into my local Maven repo with a patch, and exclude the dependency from my current build in favor of my patched version.  Hopefully, we can get it corrected in a slightly less hacky way (by getting whoever is currently interested in maintaining XPP to make the fix).

Updated: 10/11
James Agnew suggests using xpp3_min, which would address this problem.

Using Embedded MongoDB for Testing

The second problem I'm still digging into.  Since I've got some interest in testing locally and using MongoDB APIs for persistence, I want to be able to do testing with Embedded Mongo DB with my Spring Services.  Unfortunately, I'm still struggling with the upgrade for spring-data-mongodb and flapdoodle.  There's something somewhere that's changed that means that MongoDB no longer knows how to convert the data I'm working with.  I'll figure this one out eventually, but based on my research (StackOverflow and elsewhere), I'm not the first person to struggle with this challenge.

Updated 10/12
Finally figured this one out.  Some automatic configuration for MongoTemplate changed in Spring-Boot-Data after 1.5.6, and to simplify, I just added the collection names to my various calls to create/update/read/query/delete data, and the problem eventually disappeared.

Tuesday, October 8, 2019

My Experience Upgrading to HAPI Release 4.0 (part 1)


"

I'm in the process of upgrading FHIR Microservices that have been developed using HAPI on FHIR 3.6 to HAPI on FHIR 4.0.  I thought I'd share some of my experiences with the HAPI on FHIR community.

There's really about 8 key steps I had to go through, each of which took just a minute or so.

  1. Changing hapi.server.version in my pom.xml to 4.0.1
  2. Second, change the name of hapi-fhir-utiltities in my pom.xml file to org.hl7.fhir.utilities
  3. Replace all instances of org.hl7.instance.model with org.hl7.fhir.dstu2.model
  4. Undo some of the above by replacing org.hl7.fhir.dstu2.model.api with org.hl7.fhir.instance.model.api.
  5. Replace some uses of  org.hl7.fhir.dstu2.model.TemporalPrecisionEnum with ca.uhn.fhir.model.api.TemporalPrecisionEnum
  6. Change calls to getServerConformance(HttpServletRequest) to support instead getServerConformance(HttpServletRequest, RequestDetails)
  7. Eliminate calls to ServerConformanceProvider.initializeOperations() for some of my delegated conformance providers (I have a converter stack that implements STU3 and R4 FHIR APIs over top of a DSTU2 native implementation, it delegates some calls).
  8. Upgrade from Spring-Boot 1.5.6 to 2.1.1
Along the way I had some other issues to address
  1. Change some of my patched converter code to deal with API changes and R4 final changes
    1. Change import org.hl7.fhir.instance.utils.ToolingExtensions to org.hl7.fhir.dstu2.utils.ToolingExtensions 
    2. Remove references to context for various resources
    3. Clean up some other mintor changes in converters
  2. Rework my integration with Spring Cloud Sleuth so that I could use release 2.0 (required since I upgraded Spring Boot).  This wasn't FHIR related work, but was essential for the Microservice tracing stack.  Mostly I got to delete a lot of code, and just figure out how to configure a couple of key things.
  3. Change an import for LocalServerPort (necessitated by changes to Spring version changes).
All in all, the process has so far been fairly painless for dealing with a framework that has a little bit more than 10,000 lines of code (not counting about  50K lines of version converters which are hand patched).  It's taken me about 2 days to get my framework to pass all unit tests, and 90% of that was in the "other issues" space (which means you won't likely have to deal with it).  Next up, I'll be applying the upgraded framework to a half-dozen and more microservices to get them to run.  I'll let you know how that goes when I get done with it.  If all goes well, the rest of it should take me little more than a day.

     Keith



Friday, October 4, 2019

IHE PCC Call for Proposals! - Submit by Nov. 11th to be discussed at Fall Face to Face

In my inbox this am ...

IHE International
Greetings IHE Community and Industry Partners,

Today we would like to remind everyone of PCC's adoption of the continuous profile proposal and work cycle as well as put forth a Call for Proposals for the ongoing Face to Face meeting. Proposals will be due by the start of the Fall Face to Face meeting on November 11th, 2019

Interested parties are invited to submit a brief proposal for new IHE Profiles and/or White Papers to be considered for development by the PCC committee. If you are an interested party and would like to begin work on a profile with PCC within the next few months, please complete your proposal and work with the co-chairs (pcc@ihe.net) to set up a time this week to discuss your proposal during the committee's Face to Face meeting.

If you are unable to submit a proposal in time to be included at the Face to Face, you may also present your proposal during one of the bi-weekly PCC committee teleconference calls. To do this, please submit a brief proposal to this PCC Planning committee and discuss with the PCC co-chairs to be added to the agenda for one of these calls.

IHE International's New Membership Model Effective October 1, 2015

Effective October 1, 2015, IHE International is moving to a new fee-based membership. To ensure your organization can participate and advocate their proposal throughout the entire Planning and Development Cycle please read the information provided at the end of this email.  Contact membership@ihe.net to renew today. 

All Proposals must follow the structure and format of the attached Brief IHE Proposal Template, specifically addressing the following:

1.       What is the problem you propose to solve by this proposal, and how is that problem expressed in practice (e.g., a use case)?
2.       How would fixing this problem improve health care in practice?
3.       What specific components of standards could be used to solve this problem?
4.       Your proposal should identify one or more potential editor(s) in the event that the proposal is selected for further evaluation and possible development. Please include some indication of the business and/or clinical case surrounding the situation when describing the problem. For example, is there an economic motivation for addressing this problem immediately?
5.       Watch the online webinar to learn more about submitting a proposal and the proposal process.

Summary of PCC's Continuous Multi-Phase Proposal Process

1.       Submit Brief Proposals
PCC Domain Call for Proposals no longer closes. Submit a Brief Proposal with the attached form to the domain email listed below.
Committee
Domain Email
PCC Committee

2.       Committee's Proposal Review
All Proposal authors are required to present a 15 min. summary of their Brief Proposal at a committee meeting (Face to Face, or teleconference). Please anticipate participating on committee teleconferences and at Face to Face meetings during the development of your proposed work item. Face to Face meetings are held on a (roughly) quarterly basis; refer to the ITI, PCC, & QRPH Meeting wiki for more information on upcoming dates and future meetings. PCC Committee calls are held bi-weekly and invites for these meetings can be found on the PCC Committee's Google groups.

3.       Committee's Proposal Acceptance and Work Cycle
After the proposal has been presented to the committee, a summary of the work item will be posted to the PCC Planning and Technical Google Groups. At the subsequent meeting of the committee in which quorum can be obtained (either teleconference or Face to Face) the committee will hold a vote on the proposed work item. If the vote passes, the proposed work item will be accepted to begin and the committee will work with the work item's owners to schedule time on the bi-weekly calls, or determine an appropriate time for a dedicated call if necessary.

Help Promote IHE Call for Proposals

All IHE members and industry partners are invited to share this announcement with their committee mailing lists and other interested parties. Additional information is maintained on the IHE Wiki.
If you have any questions about the PCC Profile Proposal process you may reach out to the PCC co-chairs at pcc@ihe.net.

Thank you, and we look forward to your proposals!

Patient Care Coordination Co-Chairs

Thursday, September 26, 2019

Strange Dreams and Context Controls in HL7 CDA

One of the challenges of a job that requires a lot of thinking is that it's really hard to escape it sometimes.  Last night, just before I head off for a short trip to the cape, I was dreaming about context controls in CDA documents.


Did I just lose you?  Yeah, I was wondering about that myself.

The CDA Document enumerates a number of participations, and for many of these participations, fixes the contextControlCode value to "OP", a code that means Overriding and Propagating, as in the example below from the CDA R-MIM.

What the heck does this mean?

In RIM Speak, context controls describe how the participation applies to not just the act the author participation is attached to (the CDA Document), but also the acts descending downwards (in the direction of the arrows) from the act in which the participation is attached.

So, if you have a CDA Document, it can have sections (a descendant act), which can have entries (a descendant act), and those entries can reference other things (like reference ranges) and so on.  And if, at the top of the document (/ClinicalDocument/author), you say that the author is Alex, then that propagates through the act and all related acts (in the direction of the act relationship arrows) until that same type of participation is again encountered.  At that time, the new participant (Bobbie) overrides the existing one, and propagates downward as the author of all attached and decedent acts.

This behavior is crucial to the way that participations work in CDA, and fortunately, all essential participations work that way.  The way it is crucial is because you can, using XSLT  (yeah, I know, who the hell else do you that dreams in XSLT...) create an XPath expression that identifies the author (or recorder, or performer) of a particular event.

Say you are looking at an allergy in a CCDA Document.  Who's the author of this thing?  Basically, you look at the act (in this case the observation using the allergy template).  If that has an author, you stop there.  Otherwise you look to the act above it to see if it has an author, and so on, all the way to the top of the document (which is /ClinicalDocument), and which, is guaranteed (according to the CDA R-MIM and Schema) to contain at least one author.  Once you find an act that has at least ONE author, you then accumulate all authors as the author of the act.  Assuming your current context is an act that you want to find the author of, here's the XPath expression that identifies all authors of the current act.

ancestor-or-self::cda:*[cda:author][1]/cda:author

What does this say?

ComponentMeaning
ancestor‑or‑self::Starting with the current node and ascending to all of its ancestors in order through the root of the document.
cda:*Find any element ... note, that while this expression will allow traversal through both act and act-relationship links, the next element will only ever be true on acts (because only acts can have author children).
[cda:author]That contains an cda:author element 
[1]Stop after you find the first one
/cda:authorCollect ALL of the authors.

So, this will find the first act that specified an author, and collect all of the authors.  If you are trying to translate from CDA to FHIR, this is an essential tool you can use to find author, informant, subject, or other participant.

You cannot assume that just because Alex authored the document that he / she authored all acts within it.  You have to look.

One important adjustment to this.  The subject of every act is assumed to be the patient, unless subject is otherwise specified, but the patient participation is actually identified through the record target participation in CDA.  This is inference from semantics, rather than true semantics, but that's OK.  The way to adjust for that is to use the following to get to the "subject" of the act:

ancestor-or-self::cda:*[cda:subject|cda:recordTarget][1]/(cda:subject|cda:recordTarget)

You may have to fiddle a bit around the use of parentheses depending on whether you are working in XSLT 1.0 or 2.0 (or even 3.0), but you should be able to make it work.

     Keith

Wednesday, September 18, 2019

One more time ...

It's a Wednesday morning in mid-September, and those of us at the HL7 Working Group meeting will shortly be hearing from Ed Hammond and some will be awarded vases in Duke Blue, and so that means it's also time for me to award the next Ad Hoc Harley.

This next awardee is someone I'd best describe as a passionate lifetime student.  I first met this person while I was chair of the IHE Patient Care Coordination workgroup in IHE and they were just learning CDA.  I love to teach, and they absorbed just about everything I could teach and then sought out more. 

It didn't take long before the two of us could spend an hour of committee time discussing the exact way in which some small piece of CDA could be modeled so that it was just right, and the semantics meant exactly what they should.  A very strong leader, we were sure to clash on some topics, but always with mutual respect and retaining friendship even when we disagreed.  Health IT is better for those sorts of interactions, something not everyone appreciates (but I do, and so do they).

Before too long they had become CDA Certified, led a workgroup developing multiple CDA specifications and an author/editor of as many CDA implementation guides as I had.  They've been deeply involved in specifications for long term care, quality measurement, first in CDA and later in FHIR.  Most recently they've been leading terminology efforts with a team developing specifications that will aid the under served by enabling the capture of Social Determinants of Health in the HL7 Gravity Project.

I look forward to continuing to work with her, and learning what she has to teach me in this space myself as I award the next Ad Hoc Harley to ...

Lisa Nelson, BA, MBA, MMI of MaxMD


for being a lifetime student and a teacher of leaders...


Friday, September 13, 2019

Life will find a way

The defining behavior of an organization or organism is that it will resist change that is perceived to threaten its existence.  Few organizations (or organisms for that matter) fail to do so, or ever consider cases beyond which the need for their existence ceases to be present.  This is also true of work groups, committees, and organizations, even those built to address temporary situations, unless there's some very specific hayflick limit assigned to them during their creation (and even that isn't always sufficient).

So very often as change agents, we fail to take this into account when we envision change.  For example, this recent post from Z-Dogg MD on Medicare for All talks about the hidden consequences of Medicare for All.  I can't fault Z-Dogg's logic here, but what I do fault is the fundamental assumption that "other things remain the same".  Yes, if Medicare for All were to become a thing, the existence of hospitals, and medicine as a profession would certainly be threatened.

But here's the catch.  Hospitals are organizations, and medical professionals are organisms.  There's an appropriate meme for this:
 

And the challenge for many is that we won't actually understand how, or in what way the organisations and organisms threatened by these changes will adapt to the change.  But adapt they will.

One thing routinely taught in both User Experience and Informatics classes is an awareness of unintended consequences.  With any big change, there will be consequences.  In a complex system, some of those consequences are certainly going to be undesirable to those organisms or organizations whose existence is perceived to be threatened by that change.  But simple logic that assumes that the system isn't going to adapt to the change is isn't going to cut it.  Yet few will think beyond it.

In the case of Medicare for All, I can honestly say that I haven't a clue what will happen, but if hospitals are threatened, they will actively seek out ways to remain profitable.  And physicians who are accustomed to a certain level of income may in fact leave medicine, but they will eventually be replaced by others who never know that the same level of compensation (see this summary).  Other impacts might be to pressure institutions that train physicians to do so in a way that doesn't leave them with crippling debt. We know this will happen because a hole in the ecosystem ... or the economy won't be left vacant for long.






Tuesday, September 10, 2019

How Things Fall Apart


Related image

It doesn't take an evil overlord to destroy something.  Things will fall apart on their own if you simply wait long enough.

Beyond a certain size, a software project, a publication, a technical specification, or a standard becomes unmanageable.  This can be mitigated with processes, but processes executed by humans aren't nearly as a repeatable as processes managed using automation.

Let's take a look at an example of how something like this happens in standards...

In HL7 Version 2, the PV1 segment reports information about a patient visit.  An important thing happens during an inpatient or emergency department visit, which is that the patient is discharged.  You will want to know about this, in terms of both where to, and when.  In HL7 Version 2.1, where is captured in PV1-37 Discharged To Location, and when in PV1-45 Discharge Date/Time.

Let's look at the evolution of PV1-37 over time.

VersionDatatypeDescription
2.2CMComponents: <code> ^ <description>
Definition: indicates a facility to which the patient was discharged. Refer to user-defined table 0113 - discharged to location.
2.3.1CMComponents: <discharge location (IS)> ^ <effective date (TS)>
Definition: This field indicates a facility to which the patient was discharged. User-defined table 0113 - Discharged to location is used as the Hl7 identifier for the user-defined table of values for this field.
2.5.1DLDComponents: <Discharge Location (IS)> ^ <Effective Date (TS)>
Definition: This field indicates the healthcare facility to which the patient was discharged and the date.
Refer to User-defined Table 0113 - Discharged to Location for suggested values.
2.8.2DLDComponents: <Discharge to Location (CWE)> ^ <Effective Date (DTM)>
Definition: This field indicates the healthcare facility to which the patient was discharged and the date. Refer to User-defined Table 0113 - Discharged to Location in Chapter 2C, Code Tables, for suggested values.

Originally, PV1-37 was just a composite made up of a code and a description.  Between 2.2 and 2.3, the data types and description of the second part of the composite changed from <description> to <effective date (TS)>.  Why?  I don't know.  It could quite simply have been someone asking "What do they put in the description field?", and someone else responding "Usually the discharge date" and from there maybe they decided to set the data type to TS, not realizing this data was already in PV1-45. NOTE: It's really hard to say what happened because this was back in 1994.  The HL7 List Serve only tracks back to 2012 for pafm and V2 lists, and the historical tracker database only goes back to Version 2.5, which came out in 2006/7 time frame, and the ballot desktop only goes back to 2004.

In the 2.4-2.5 time frame the CM data type was replaced with a real data type (DLD), which was defined as being an IS followed by a TS.  That we can determine from change request 135 in the HL7 change tracking database for Version 2.

Over time, IS data types were switched to CWE data types, and TS to DTM as you can see in Version 2.8.2 above.

So, somewhere along the way, we lost track of why <description> became <effective date>, and duplicated what was already in PV1-45 Discharge Date/Time.

People move on, knowledge gets lost, cruft and minor issues accumulate, technical debt accrues.  Eventually, technology needs to be rebuilt, just like anything else, in order to be relevant, useful and most of all, well understood by all currently using it, or it collapses under its own weight.