Friday, August 18, 2023

GSoC Week 11: A Journey of Refinement and Innovation in FHIR2 Module

Introduction:

Greetings, fellow enthusiasts of healthcare technology and data interoperability! The journey through Google Summer of Code (GSoC) continues, and as I step into the 11th week, I find myself in the midst of a captivating process of refining and innovating within the OpenMRS FHIR2 module. Building upon the foundations laid in the previous week, I'm excited to share the progress made and the steps taken to enhance the attribute-to-contact-point configuration process. Join me as we explore the intricacies of this journey of refinement and innovation!

A Continuation of Progress:

Week 11 has been a seamless continuation of the work initiated in the previous week. With the guidance of my mentor, I have been actively engaged in refining the pull request initiated in week 10 (https://github.com/openmrs/openmrs-module-fhir2/pull/517). This pull request addresses a critical aspect of configuring attributes as contact points, focusing on ensuring the uniqueness of the combination of attribute_type_domain and attribute_type_id.

Unique Combinations: The Logic Behind the Scenes:

One of the key challenges when dealing with attributes as contact points lies in preventing the duplication of data. This week, the spotlight has been on devising logic that ensures each combination of attribute_type_domain and attribute_type_id remains unique. This logic is essential to maintain data integrity and prevent conflicts within the system.

Suggested Approach: Loading and Updating Existing Values:

To tackle this challenge, a suggestion has been made to load the existing value for a specific combination and update it if it already exists. This approach leverages the power of data retrieval and manipulation to efficiently manage attribute-to-contact-point configurations. By employing this technique, we ensure that the uniqueness constraint is upheld while providing a seamless experience for users and administrators.

Below is the snippet i added to address the changes suggested by my mentor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
	@Override
	public FhirContactPointMap saveFhirContactPointMap(@Nonnull FhirContactPointMap contactPointMap) {
		FhirContactPointMap existingContactPointMap = (FhirContactPointMap) sessionFactory.getCurrentSession().createQuery(
		    "from FhirContactPointMap fcp where fcp.attributeTypeDomain = :attribute_type_domain and fcp.attributeTypeId = :attribute_type_id")
		        .setParameter("attribute_type_domain", contactPointMap.getAttributeTypeDomain())
		        .setParameter("attribute_type_id", contactPointMap.getAttributeTypeId()).uniqueResult();
		
		if (existingContactPointMap != null) {
			existingContactPointMap.setSystem(contactPointMap.getSystem());
			existingContactPointMap.setUse(contactPointMap.getUse());
			existingContactPointMap.setRank(contactPointMap.getRank());
			sessionFactory.getCurrentSession().merge(existingContactPointMap);
			return existingContactPointMap;
		} else {
			sessionFactory.getCurrentSession().saveOrUpdate(contactPointMap);
			return contactPointMap;
		}
	}

Let's break down the code and discuss its functionality:

Explanation:

  • The method takes a `FhirContactPointMap` object (`contactPointMap`) as a parameter and returns a `FhirContactPointMap` object.
  • The code queries the database to check if there is an existing `FhirContactPointMap` with the same `attributeTypeDomain` and `attributeTypeId`. This is done using Hibernate's Query Language (HQL).
  • If an existing map is found, its `system`, `use`, and `rank` values are updated with the values from the `contactPointMap` parameter. The `merge` method is used to update the existing entity.
  • If no existing map is found, the `saveOrUpdate` method is used to either save a new `contactPointMap` or update an existing one, based on its state.

This method essentially checks whether a given `FhirContactPointMap` already exists in the database based on the specified attributes (`attributeTypeDomain` and `attributeTypeId`). If it exists, the method updates its values; otherwise, it creates a new entry or updates an existing one.

Mentorship and Collaboration: Navigating Complex Challenges:

As with any intricate technical challenge, mentorship and collaboration have played a pivotal role in navigating through the complexities. My mentor's insights and guidance have been invaluable in devising the most effective and elegant solutions. Collaborative discussions and code reviews have provided fresh perspectives and refined the implementation, aligning it with best practices and the standards of the OpenMRS community.

The Road Ahead: Beyond Configuration:

As week 11 draws to a close, I'm filled with a sense of accomplishment and eagerness for what lies ahead. The journey of refining and innovating within the FHIR2 module is a testament to the spirit of continuous improvement and the drive to enhance healthcare data interoperability. Beyond attribute-to-contact-point configuration, this experience underscores the broader mission of GSoC – to contribute to meaningful solutions that impact patient care and healthcare technology.

Conclusion:

Week 11 has been a captivating chapter in the GSoC journey, marked by diligent refinement and the pursuit of innovative solutions. The process of ensuring unique combinations of attributes within the FHIR2 module represents a microcosm of the larger goal – to create a more connected, efficient, and effective healthcare ecosystem.

As I look ahead to the final weeks of GSoC, I'm invigorated by the progress made and inspired by the collaborative spirit that drives the OpenMRS community. Join me as we continue to push the boundaries of healthcare technology and explore new frontiers in the quest for excellence.

Thank you for being a part of this incredible journey. Until next time, let's keep pushing forward and making a positive impact!

Thursday, August 10, 2023

Embracing the Finale: Reflecting on My GSoC Journey - GSoC Week 10



Introduction:

Greetings, dear readers! It's with a mix of emotions that I pen down this blog post, for the end of my Google Summer of Code (GSoC) journey is drawing near. As I look back on the incredible weeks that have led me to this point, I'm filled with a sense of accomplishment, gratitude, and a touch of nostalgia. Join me as I reflect on the experiences, challenges, and growth that have defined this remarkable journey.

A Journey of Learning and Growth:

The past weeks of GSoC have been a whirlwind of coding challenges, collaboration with mentors and peers, and a continuous drive to make meaningful contributions. From delving into the complexities of healthcare interoperability to mastering the nuances of the OpenMRS data model, every step of this journey has been a learning opportunity.

New Horizons: Mapping FHIR Contact Points to OpenMRS Data Model:

In the realm of healthcare data interoperability, mapping data structures from one standard to another can be both fascinating and complex. One such challenge arises when we consider "Contact Points" in FHIR and their representation in OpenMRS. In this blog post, we'll explore the intricacies of this mapping process, particularly focusing on the intriguing concept of determining the priority or "rank" of different values. Join me as we delve into the world of Contact Points and unravel the puzzle of priorities!

Understanding Contact Points in FHIR and OpenMRS:

In the Fast Healthcare Interoperability Resources (FHIR) standard, Contact Points play a vital role in representing various means of contacting an individual, such as phone numbers, emails, faxes, and pagers. These contact details hold different types and values, providing comprehensive ways to reach out to patients, providers, and other stakeholders.

On the other hand, OpenMRS manages these types of data through Attributes. Attributes like PersonAttributes, LocationAttributes, and ProviderAttributes are used to store additional information about persons, locations, and providers. While the structure seems clear, a significant challenge arises when we consider the ranking or priority of these values.

Prioritizing Values: The FHIR "Rank" Conundrum:

FHIR introduces the concept of "rank" to indicate the relative priority of different contact values. For example, if a patient has multiple phone numbers, the rank helps determine which phone number should be preferred for communication. This prioritization ensures efficient and effective contact strategies. In the OpenMRS ecosystem, this notion of "rank" is not inherently present. The challenge lies in translating FHIR's rank-based approach into OpenMRS's attribute-based system. How do we decide which phone number or email to prioritize when contacting a patient?

Solution

The solution we came up with was to create a mapping table called fhir_contact_points_map between attribute and attribute_type that would store values like system, use and rank. It is those values what we translate in the telecom translator. Catch the ongoing work at https://github.com/openmrs/openmrs-module-fhir2/pull/517/files

The Joy of Collaboration:

The heart of open-source development lies in collaboration. Through code reviews, discussions, and interactions with the OpenMRS community, I've come to appreciate the power of collective wisdom. Collaborating with experienced mentors and learning from their feedback has been instrumental in elevating the quality of my work.

Celebrating Milestones:

Looking back, I can't help but celebrate the milestones achieved during this journey. From implementing critical features to squashing bugs and enhancing documentation, each achievement has contributed to the evolution of the OpenMRS FHIR2 module. These accomplishments wouldn't have been possible without the encouragement and support of the community.

Personal Growth and Beyond:

Beyond the code, GSoC has been a catalyst for personal growth. I've become a more resilient problem-solver, a better communicator, and a more effective collaborator. These skills extend beyond the realm of technology, enriching my journey both as a developer and as an individual.

A Bittersweet Farewell:

As GSoC reaches its conclusion, I can't help but feel a bittersweet mix of emotions. While saying goodbye to this chapter is not easy, I'm filled with gratitude for the experiences, connections, and insights I've gained. GSoC has been more than just a coding program; it's been a transformative experience that will resonate in my journey ahead.

Conclusion:

As I bid adieu to GSoC, I want to express my heartfelt gratitude to the OpenMRS community, mentors, peers, and readers like you who have been a part of this journey. The end might be nigh, but the memories, lessons, and connections forged during these weeks will endure. This is not the end, but a stepping stone to new endeavors, fresh challenges, and a continued commitment to the open-source spirit.

Thank you for joining me on this adventure. Here's to the end and to new beginnings! Until we meet again.

Cheers!

Thursday, August 3, 2023

GSoC 2023 at OpenMRS | Coding Period Week 09

 

Introduction

Welcome back to my GSoC journey at OpenMRS! Week 9 has been an exciting and challenging phase as i continued my work on the OpenMRS Fhir2 module. After successfully completing the patching operations, i eargerly embarked on the next task from my mentor which is support Etags on the module. In this blog post i will share my experiences, achievements and the lessons i have learned during this week of my project.

Understanding Etags

Before diving into the implementation, i spent sometime researching and understanding what Etags are and their use. Etags, short for "entity tags", are a mechanism used for resource versioning and caching in web applications. In the context of FHIR, Etags play a crucial role in ensuring efficient communication between clients and servers. They provide a way for clients to keep track of resource versions and determine if resources have been updated on the server since they were last retrieved. So the purpose of this task was to trigger HAPI FHIR's support for FHIR's Etag spec which uses the weak Etag's for the version id.

Note: this algorithm could result in the FHIR API reporting a changed Etag where the REST API does not which is because the Etag/versionId in FHIR API is derived entirely from the lastUpdated timestamp.

Here is the ticket -> https://issues.openmrs.org/browse/FM2-605.

Here is what i did to that effect

  • I added the logic to generate and manage Etags for each resource using the version id which derived from the lastUpdated timestamp. So whenever a resource is updated, its Etag is automatically updated. 
  • I added unit tests and integration tests to ensure the functionality works to perfection and ofcourse ensure that it doesn't break the existing tests and functionality.

Explanation of how it works in OpenMRS

When a GET request is sent out to the server to retrieve a resource for example Patient Resource with a given uuid i.e 3d50d0c2-257e-4262-a48b-3e9b3dbffefd, the response is returned and inside the response header, comes an etag too ie  ETag: W/"3141" . So when the user attempts to send another request to the server with the attached if-None-match header containing the above etag, the server returns a 304 status code response if the resource has not changed since the last retrieval. If the resource has changed then a 200 status code will be returned with the latest version of the resource and a new Etag. 

Resources i used



Until next time,
Cheers

Monday, July 24, 2023

GSoC 2023 at OpenMRS | Coding Period Week 08

 


Introduction

Greetings, readers!

Welcome to my blog documenting my incredible journey through the 8th week of Google Summer of Code (GSoC). Over the past weeks, i have had the privilege of working with the OpenMRS community, contributing to the fhir2 module. With each passing week, i have learned and grown as a developer, and the 8th week was no exception. Let's dive into the highlights of the eventful week!

Highlights

Add Support for Patch Operations on Immunization resource

implemented all patch operations on the Immunization resource i.e Json Merge Patch, Json Patch and Xml Patch. This one needed careful handling since it was being saved as an Obs object.

Add Support for Update and Patch on Observation resource

this was continuation from last week and i had not yet figured out i was losing the functionality of creating a new obsid when patching an observation like it is in updating an obs object. However, i achieved that and it was more to do with the data set i was using for the integration test.

Others include:

Conclusion

The 8th week was a whirlwind of challenges and accomplishments. The support and mentorship from Ian Bacher and Abert Namanya and the entire community has been instrumental in my growth as a developer.

As i reflect on last week's achievements, i am reminded of the power of open-source collaboration and the impact we make by working together. GSoC has been an unforgettable experience, and i am excited to continue contributing to open-source beyond this program.

Thank you for joining me on this incredible journey. Stay tuned for more updates as i embark on the final leg of GSoC, with new challenges and opportunities awaiting.

Until next time!
Cheers!

Monday, July 17, 2023

GSoC 2023 at OpenMRS | Coding Period Week 07

Introduction

Greetings, dear readers!

I am delighted to share with you an update on my exhilarating coding journey during WEEK 7 of the Google Summer of Code (GSoC) program. This incredible experience has allowed me to delve into the depths of programming, further honing my skills and embracing new challenges along the way.

Over the past 6 weeks, i have been engaged in an exciting project called Add Support for FHIR Patch operations. The program has provided me with an invaluable platform to collaborate with mentors and work on a real-world software development project. To have a recap of how the six weeks have been, please look through my weekly blogs so far.  You can aswell find the short demo video for my midterm evaluation at https://www.youtube.com/watch?v=P-0gj-8LOCE.

Week 7 Recap

In week 7 i embarked on completing the resources that i had not yet covered for XML PATCHing which included Location resource, Encounter resource. Below are the pull requests for the two resources:-

As part of week 7, i also attempted an issue to clean up parameter passing on the condition resource. I realized there is a little more work needed in making the right functionality come out. This is so because the OpenMRS FHIR implementation of the Condition Resource was twice because in the versions below OpenMRS 2.2.0, the Condition resource was not supported. So the translation of that resource in the Fhir2 module was based off of the Obs object. And in the second implementation, it was based off the Condition object which was introduced in the openmrs data model in the versions 2.2.0 and above. The integration tests for the versions below 2.2.0 were not properly written since they included the clinicalStatus which wasn't part of that particular version. Below is the pull request for that more.
The task i had in Week 7 was to ensure that the Observation Resource supports PATCHing operations. However, to introduce that i had to ensure that it can support UPDATING requests which i did in the commit below:-
Maybe a little context of what actually takes place here, the Obs object in OpenMRS is a unique object and hence usually refered to as immutable. This can further be explained that when an existing obs object is edited/updated, the existing obs object with the existing obsId is voided and a new obs object with a new obsId is created hence a new row in the database altogether.
After supporting UPDATE, next task i attempted was ensuring that it supports PATCHing. However, the challenge here that has blocked me from completing this task this week is that unlike the UPDATE which voids the existing obs object when updating it, with PATCHing the behavious is not really coming out as it should. It does not void the exisiting obs object hence returning the same object but patched. The saveObs() method seems to consider the patched object  as a saveObsNotDirty() yet it is supposed to be a saveExistingObs(). Below is the commit for patching;-

Looking Ahead

As i step into the 8th week, i remain confident that the challenges i am having on Observation Resource will be overcome and it will be able to support PATCHing as it should. I will continue to follow the project timeline diligently, seeking guidance from my mentors and the entire community and give feedback when needed to ensure the successful completion of my assigned tasks.

Stay tuned for more updates as i continue this exhilarating journey! 
Thank you for joining me on this blog post, and until next time!

cheers,
mherman22

Monday, July 10, 2023

GSoC 2023 at OpenMRS | Coding Period Week 06

 

Welcome to the sixth week of my Google Summer of Code (GSoC) journey! It's hard to believe how quickly time has flown by as I continue to dive deeper into my project and explore new territories. This week has been full of exciting challenges and rewarding accomplishments, pushing me further towards my goals.

Throughout the program, I have had the opportunity to work closely with dedicated mentors and a vibrant community of like-minded developers at OpenMRS. Their guidance and support have been invaluable in shaping my understanding the FHIR Api and how OpenMRS leverages its functionality. As I reflect on the progress made so far, I am filled with a sense of gratitude and enthusiasm for the road ahead.

In this blog post, I will delve into the highlights and key learnings from the sixth week of my GSoC project. I will share the hurdles I encountered, the strategies I employed to overcome them, and the valuable insights gained along the way. Additionally, I will provide updates on the project's overall direction and discuss the exciting features and improvements implemented during this period.

Join me as I recount the fascinating moments, breakthroughs, and challenges encountered in the sixth week of my GSoC journey. I hope that my experiences and insights can inspire and resonate with fellow developers, and perhaps even offer valuable takeaways for those embarking on similar endeavors.

Without further ado, let's dive into the adventures of the past week and explore the strides taken towards making a meaningful contribution to the open-source community through my GSoC project.

Goal of the week

  • Ensure that XML PATCHing works as it should on all the Fhir Resources that support patching in the OpenMRS Fhir2 Module. They should be able to take in an xml document like the one shown below:
<?xml version="1.0" encoding="UTF-8" ?>
<!--
    This Source Code Form is subject to the terms of the Mozilla Public License,
    v. 2.0. If a copy of the MPL was not distributed with this file, You can
    obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
    the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
    Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
    graphic logo is a trademark of OpenMRS Inc.
-->
<diff xmlns:fhir="http://hl7.org/fhir">
	<replace sel="/fhir:MedicationDispense/fhir:status/@value">
		completed
	</replace>
</diff>

Let us break down the xml document for better understanding of what is going on there:-
  1. The root element is named diff and it belongs to the XML namespace "http://hl7.org/fhir". Namespaces allow for the differentiation of elements with the same name but belonging to different contexts or specifications. 
  2. Within the diff element, there is a child element named replace. It specifies the XPath expression sel attribute which selects a specific attribute value in the XML document. In this case, it selects the value attribute of the status element under the MedicationDispense element in the FHIR namespace. The text content within the replace element is completed, indicating the new value that will replace the selected attribute's current value.Therefore, the above XML patch document  modifies an existing XML document in the OpenMRS Fhir2 Module.

Highlights / Pull Requests


Thanks for taking time to go through the blog! 
Nice week ahead, cheers!

Sunday, July 2, 2023

GSoC 2023 at OpenMRS | Coding Period Week 05

 


 Welcome to this week's blog that gives an account of what happened last week as I continue in this journey. Last week was an eventful week in terms of getting most of my pull requests merged into the openmrs-module-fhir2. Most of these pull requests were catering for JSON PATCHing and XML PATCHing operations.

The merged pull requests include the following:-

For the past week i have looked into https://issues.openmrs.org/browse/FM2-591 which ensures to fully translate the ServiceRequest Fhir Resource into the OpenMRS datamodel's object called TestOrder. I created a talk post at https://talk.openmrs.org/t/toopenmrstype-translator-for-servicerequest-should-be-implemented/39980/1 where i needed help in translating some elements of the ServiceRequest resource like intent, status and performer

During our weekly meetings, my mentors took me through how i should overcome the issue. For the intent element, there is no need to translate it to openmrsType since it is hardcoded as ServiceRequest.ServiceRequestIntent.ORDER.

For performer. i would have to reverse engineer the current implement in the toFhirResource method.  Here is the method to reverse engineer. and after doing so i will go through all the other elements that need to be translated and hopefully have this implemented this week.

	private Reference determineServiceRequestPerformer(String orderUuid) {
		IBundleProvider results = taskService.searchForTasks(new TaskSearchParams(
		    new ReferenceAndListParam()
		            .addAnd(new ReferenceOrListParam().add(new ReferenceParam("ServiceRequest", null, orderUuid))),
		    null, null, null, null, null, null));
		
		Collection<Task> serviceRequestTasks = results.getResources(START_INDEX, END_INDEX).stream().map(p -> (Task) p)
		        .collect(Collectors.toList());
		
		if (serviceRequestTasks.size() != 1) {
			return null;
		}
		
		return serviceRequestTasks.iterator().next().getOwner();
	}

With the merging of the above pull requests that catered for JSON PATCHing, JSON MERGE PATCHing and the XMLPATCHUtils class that introduces XML PATCHing, i can now(this week) move onto writing integration tests for the other resources to ensure and confirm they implement XML Patching operations.

Thanks for taking time and reading through.