Wikum Weerakutti

GSOC-2023: Coding Week 02

As I hoped in week one, I was able to implement building the O3 using the OpenMRS SDK.However, I haven't still done the maven release for these changes yet, I'll be able to do it within a few days. Before discussing how I implemented the feature, let me explain how to build the O3 using the SDK.

There are two ways to deploy the O3 using the SDK.

Set up the O3 distribution with the SDK

This is fairly easy to use. You just need to run the SDK with the following command.

mvn openmrs-sdk:setup

Then, when you are prompted with this, Select "O3 Distribution" by entering the corresponding number:

You can set up the following servers:
1) 2.x Distribution
2) Platform
3) O3 Distribution
Which one do you choose? [1/2/3]:

After choosing "O3 Distribution," you will be prompted to select the desired version. Once selected, the SDK will handle the rest. Simply follow the prompts to configure the server port, database details, and Java version as required.

Set up the O3 with a custom distro.properties file (advanced users)

This method is recommended for advanced users who want to customize their setup according to their preferences. To begin, create a "distro.properties" file similar to the one shown below:

name=Ref 3.x distro
version=3.0.0
war.openmrs=2.6.1-SNAPSHOT
config.referenceapplication-distro=3.0.0-SNAPSHOT
omod.addresshierarchy=2.15.1
omod.appointments=1.6.0
omod.appointments.groupId=org.bahmni.module
omod.attachments=3.0.0
omod.calculation=1.3.0
omod.cohort=3.4.0
omod.fhir2=1.9.0
omod.htmlwidgets=1.11.0
omod.idgen=4.10.0
omod.initializer=2.5.0
omod.legacyui=1.15.0
omod.metadatamapping=1.6.0
omod.metadatasharing=1.9.0
omod.openconceptlab=2.1.0
omod.ordertemplates=1.0.2-SNAPSHOT
omod.owa=1.14.0
omod.queue=1.0.0-alpha.1
omod.referencedemodata=2.4.0-SNAPSHOT
omod.reporting=1.25.0
omod.reportingrest=1.14.0
omod.serialization.xstream=0.2.16
omod.serialization.xstream.type=omod
omod.spa=1.0.10-SNAPSHOT
omod.webservices.rest=2.40.0-SNAPSHOT
spa.frontendModules.@openmrs/esm-active-visits-app=next
spa.frontendModules.@openmrs/esm-appointments-app=next
spa.frontendModules.@openmrs/esm-cohort-builder-app=next
spa.frontendModules.@openmrs/esm-devtools-app=next
spa.frontendModules.@openmrs/esm-dispensing-app=next
spa.frontendModules.@openmrs/esm-fast-data-entry-app=next
spa.frontendModules.@openmrs/esm-form-builder-app=next
spa.frontendModules.@openmrs/esm-form-entry-app=next
spa.frontendModules.@openmrs/esm-generic-patient-widgets-app=next
spa.frontendModules.@openmrs/esm-home-app=next
spa.frontendModules.@openmrs/esm-implementer-tools-app=next
spa.frontendModules.@openmrs/esm-login-app=next
spa.frontendModules.@openmrs/esm-offline-tools-app=next
spa.frontendModules.@openmrs/esm-openconceptlab-app=next
spa.frontendModules.@openmrs/esm-outpatient-app=next
spa.frontendModules.@openmrs/esm-patient-allergies-app=next
spa.frontendModules.@openmrs/esm-patient-appointments-app=next
spa.frontendModules.@openmrs/esm-patient-attachments-app=next
spa.frontendModules.@openmrs/esm-patient-banner-app=next
spa.frontendModules.@openmrs/esm-patient-biometrics-app=next
spa.frontendModules.@openmrs/esm-patient-chart-app=next
spa.frontendModules.@openmrs/esm-patient-conditions-app=next
spa.frontendModules.@openmrs/esm-patient-forms-app=next
spa.frontendModules.@openmrs/esm-patient-list-app=next
spa.frontendModules.@openmrs/esm-patient-medications-app=next
spa.frontendModules.@openmrs/esm-patient-notes-app=next
spa.frontendModules.@openmrs/esm-patient-programs-app=next
spa.frontendModules.@openmrs/esm-patient-registration-app=next
spa.frontendModules.@openmrs/esm-patient-search-app=next
spa.frontendModules.@openmrs/esm-patient-test-results-app=next
spa.frontendModules.@openmrs/esm-patient-vitals-app=next
spa.frontendModules.@openmrs/esm-primary-navigation-app=next

Once the "distro.properties" file is ready, run the following command:

mvn openmrs-sdk:setup -Ddistro=distro.properties

To ensure you have the most up-to-date and detailed instructions on setting up O3, I recommend referring to the official documentation. It provides the latest version of the guide and is highly recommended for following the setup process.

Now, let's dive into what I accomplished during the second week to achieve this goal.

Implementation

At the end of the first week, I successfully implemented the feature that allows users to build O3 using a custom distro.properties file. For the second week, my task was to add a feature that enables users to set up O3 without the need for a custom-made distro.properties file. However, this presented a few challenges that needed to be addressed.

To overcome these challenges, I initially developed a method to automatically generate a distro.properties file. The process involved the following steps:

Generating a distro.properties file

  1. Obtain a template for the distro.properties here: https://raw.githubusercontent.com/openmrs/openmrs-distro-referenceapplication/main/distro/distro.properties
  2. Retrieve the version for backend modules from this: https://github.com/openmrs/openmrs-distro-referenceapplication/blob/main/distro/pom.xml
  3. Replace placeholders in the distro.properties template with the versions of backend modules.
  4. Extract the frontend modules from https://raw.githubusercontent.com/openmrs/openmrs-distro-referenceapplication/main/frontend/spa-build-config.json and add those to the distro.properties file.
  5. Get the configuration version using https://github.com/openmrs/openmrs-distro-referenceapplication/blob/2d2bbaad52b350089a9cdd6595350e5faa8a72de/distro/pom.xml#LL4C2-L8C12.0
  6. Get the SPA module version from https://github.com/openmrs/openmrs-module-spa/blob/589f30b837f87d5cae885eb4ee1c06ed3e2af5e5/pom.xml#L7.
  7. Generate the file and build the server

I implemented this code and pushed it to GitHub. However, during the code review with my mentors, we identified a few problems.

ERROR - ReferenceDemoDataActivator.started(227) |2023-06-06T18:50:55,907| Exception caught while creating demo data
org.openmrs.api.ValidationException: 'Patient#null' failed to validate with reason: names[0].familyName: FamilyName.invalid
    at org.openmrs.validator.ValidateUtil.validate(ValidateUtil.java:88) ~[openmrs-api-2.6.1-SNAPSHOT.jar:?]
    at org.openmrs.aop.RequiredDataAdvice.before(RequiredDataAdvice.java:128) ~[openmrs-api-2.6.1-SNAPSHOT.jar:?]
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:57) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.23.jar:5.3.23]
    at com.sun.proxy.$Proxy294.savePatient(Unknown Source) ~[?:?]
    at org.openmrs.module.referencedemodata.patient.DemoPatientGenerator.createDemoPatient(DemoPatientGenerator.java:80) ~[referencedemodata.jar:?]
    at org.openmrs.module.referencedemodata.patient.DemoPatientGenerator.createDemoPatients(DemoPatientGenerator.java:58) ~[referencedemodata.jar:?]
    at org.openmrs.module.referencedemodata.ReferenceDemoDataActivator.started(ReferenceDemoDataActivator.java:116) ~[referencedemodata.jar:?]
    at org.openmrs.module.ModuleUtil.refreshApplicationContext(ModuleUtil.java:922) ~[openmrs-api-2.6.1-SNAPSHOT.jar:?]
    at org.openmrs.module.web.WebModuleUtil.refreshWAC(WebModuleUtil.java:923) ~[openmrs-web-2.6.1-SNAPSHOT.jar:?]
    at org.openmrs.web.Listener.performWebStartOfModules(Listener.java:703) ~[openmrs-web-2.6.1-SNAPSHOT.jar:?]
    at org.openmrs.web.Listener.performWebStartOfModules(Listener.java:683) ~[openmrs-web-2.6.1-SNAPSHOT.jar:?]
    at org.openmrs.web.Listener.startOpenmrs(Listener.java:349) ~[openmrs-web-2.6.1-SNAPSHOT.jar:?]
    at org.openmrs.web.WebDaemon$1.run(WebDaemon.java:42) ~[openmrs-web-2.6.1-SNAPSHOT.jar:?]

My mentor Daniel fixed this issue with this commit

In the commit, you'll notice that he made the following change:

private static final String[] FAMILY_NAMES = { "Smith", "Johnson", "Williams", "Brown", "Jones", "Miller", "Davis",
"García", "Rodríguez", "Wilson", "Martínez", "Anderson", "Taylor", "Thomas", "Hernández", "Moore", "Martin",
"Jackson", "Thompson", "White", "López", "Lee", "González", "Harris", "Clark", "Lewis", "Robinson", "Walker",
"Pérez", "Hall", "Young", "Allen", "Sánchez", "Wright", "King", "Scott", "Green", "Baker", "Adams", "Nelson",
"Hill", "Ramírez", "Campbell", "Mitchell", "Roberts", "Carter", "Phillips", "Evans", "Turner", "Torres", "Odinga" };

This has been changed to:

private static final String[] FAMILY_NAMES = { "Smith", "Johnson", "Williams", "Brown", "Jones", "Miller", "Davis",
"Garcia", "Rodriguez", "Wilson", "Martinez", "Anderson", "Taylor", "Thomas", "Hernandez", "Moore", "Martin",
"Jackson", "Thompson", "White", "Lopez", "Lee", "Gonzalez", "Harris", "Clark", "Lewis", "Robinson", "Walker",
"Perez", "Hall", "Young", "Allen", "Sanchez", "Wright", "King", "Scott", "Green", "Baker", "Adams", "Nelson",
"Hill", "Ramirez", "Campbell", "Mitchell", "Roberts", "Carter", "Phillips", "Evans", "Turner", "Torres", "Odinga" };

As you can see, he replaced the Latin characters. We are currently investigating why those characters are accepted by dev3.openmrs.org but not on the local environment.

To allow users to deploy multiple versions of O3, I made some modifications to the code. Although the initial code I wrote for auto-generating the distro.properties file became somewhat obsolete, it still proved useful during the final implementation.

Final Implementation

The final implementation of the code to allow users to deploy multiple versions of O3 works as follows:

  1. When the user selects they want to deploy "O3 Distribution" code will retrieve all the available versions of "org.openmrs.distro:referenceapplication-distro" and display them to the user.
  2. After the user selects what version they need, the code follows the following method to find the necessary module dependencies.
  3. With these the SDK creates a suitable distro.properties file and set up the O3 server.

Conclusion

After overcoming various challenges and making necessary modifications, I successfully implemented the feature that allows users to deploy multiple versions of O3 without the need for a custom-made distro.properties file. This functionality enhances the flexibility and ease of setting up O3 for different users with different requirements.

By providing users with the ability to choose their desired O3 version and automatically retrieving the required backend and frontend modules, the setup process has been streamlined, making it more accessible to a wider range of users.

I'm excited about the progress made during the second week and the positive impact it will have on the SDK and O3 project. I look forward to continuing my work on the SDK and further contributing to its development in the upcoming weeks.

Thank you for reading, see you next week!