Haiti Metadata Module

Hi Mark,

The upgrade to metadatadeploy from 1.7 to 1.8.1 is required because I couldn’t load the module. It would give a hibernate error.

Let me check the emrapi…

Ok, I removed both of the emrapi and serialization.xstream modules, keeping the openmrsversion at 1.10.4. Everything builds fine and loads into OpenMRS platform 2.0.1 without errors. When I update the openmrsversion to 2.0.1 in the pom.xml file, I get failed tests because the observationmapper isn’t recognized. I can add the -DskipTests flag, build and load the module fine.

Should I add another commit that removes the additional serialization.xstream and emrapi dependencies?

Thanks for your patience with me on this! Craig

No worries, I’ll go ahead and pull these out!

The only reason we’d need to compile and test against 2.0.1 would be if 1) we wanted to start to use 2.x functionality, or 2) to confirm & test that we aren’t using any functionality that has been removed/changed in 2.x.

The first won’t be an issue until we upgrade, as for the second, it’s possible and will be something we’ll need keep an eye out for. It’s also possible that we could prioritize upgrading to 2.0 to avoid having to worry about this.

Take care, Mark

Craig,

If we think this is working, does it make sense to start adding some of patient registration metadata so we can standardize, since it sounds like you are working on registration now?

Take care, Mark

Yes!

We will standardize on your process. Why did you guys choose to create separate encounterTypes and forms for each section instead of capturing them all in one encounterType and form?

Cool, thanks @craigappl. What’s your timeframe? I’ll aim to schedule some time in the next week or two to get the metadata in Haiti Core, but if you have any pressing deliverables, let me know.

Even though there are four HTML Forms we use (one for each of the following sections: Registration, Insurance Company Name, Social, and Contact Person), they are all backed by the same encounter of type “Registration Encounter”. So we only have a single encounter type and encounter per registration. (The “Demographics” and “Contact Info” sections collect non-obs data and are hardcoded into the Registration App.)

I’m not sure we had a particularly good reason for making each section separate, and I don’t know if we are married to it as this point. We didn’t do the initial development of the Registration App, and when we went to adopt it, the “Demographics” and “Contact Info” sections had already been implemented, with separate edit sections for each. To be consist with this pattern, we created a separate edit form for each summary section.

Take care, Mark

Thanks @mogoodrich. We don’t have a pressing deadline. I’d like our team to contribute code to this module over the coming week based on the work in the PIHcore repo so we can get up to speed on supporting this module. We’ll start with creating the single encounterType for patient registration, then work to import the address template, then addresshierarchy.

Does that sound like a good start?

FYI @jamesfeshner @jmaxy

Do you mean you want your team to take a stab at migrating some of the code from PIH Core to Haiti Core so your team can get a feel for how things work? I wouldn’t complain at others picking up the work! Feel free to hit me up with any questions.

Take care, Mark

Yes, that’s what we’re proposing :slight_smile: @jamesfeshner will be the one to pick it up. He’ll post questions here as he works through these first three pieces.

Great, thanks! Please do post any questions.

Take care, Mark

Hi @mogoodrich,

This is a note based on the PR I just submitted

The first commit where I add the patient registration encounter type is working on both 1.10.4 and 2.0.5. I also committed the code to add the address template and address hierarchy. The builds are passing on 1.10.4, but I haven’t tried it by loading in.

I upgraded the dependencies to work on OpenMRS 2.0.5 on another branch (here’s the relevant commit)and need your help.

  1. The Address Template class changed in OpenMRS 2.0 and it isn’t backwards compatible to 1.10.x, so I had to create a workaround based on the Ajir module in Uganda using the reflection method to support the change in the location of the class.

  2. I had to upgrade jackson from 1.5 to 1.8.3 to get it to build

  3. Once it got it to build, I’m getting an tomcat error when I load the module into OpenMRS 2.0.5. The following error looks like org.openmrs.module.addresshierarchy.AddressField isn’t loading in appropriately and I can’t figure out why. @dkayiwa if you have a few moments, have you run into this as well?

    org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: org/openmrs/module/addresshierarchy/AddressField org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletionWithError(DispatcherServlet.java:1287) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868) javax.servlet.http.HttpServlet.service(HttpServlet.java:646) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) javax.servlet.http.HttpServlet.service(HttpServlet.java:727) org.openmrs.module.web.filter.ForcePasswordChangeFilter.doFilter(ForcePasswordChangeFilter.java:60) org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:72) org.openmrs.module.owa.filter.OwaFilter.doFilter(OwaFilter.java:57) org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:70) org.openmrs.module.web.filter.ModuleFilter.doFilter(ModuleFilter.java:54) org.openmrs.web.filter.OpenmrsFilter.doFilterInternal(OpenmrsFilter.java:108) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:150) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105) org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105) org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

root cause

java.lang.NoClassDefFoundError: org/openmrs/module/addresshierarchy/AddressField org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.HaitiAddressBundle.getAddressComponents(HaitiAddressBundle.java:22) org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.AddressBundle.getAddressTemplate(AddressBundle.java:78) org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.AddressBundle.installAddressTemplate(AddressBundle.java:66) org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.AddressBundle.installEveryTime(AddressBundle.java:41) org.openmrs.module.metadatadeploy.bundle.VersionedMetadataBundle.install(VersionedMetadataBundle.java:30) org.openmrs.module.metadatadeploy.api.impl.MetadataDeployServiceImpl.installBundle(MetadataDeployServiceImpl.java:111) org.openmrs.module.metadatadeploy.api.impl.MetadataDeployServiceImpl.installBundle(MetadataDeployServiceImpl.java:81) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:498) org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) com.sun.proxy.$Proxy370.installBundle(Unknown Source) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:498) org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) com.sun.proxy.$Proxy512.installBundle(Unknown Source) org.openmrs.module.haiticore.HaitiCoreActivator.installMetadataBundles(HaitiCoreActivator.java:47) org.openmrs.module.haiticore.HaitiCoreActivator.started(HaitiCoreActivator.java:33) org.openmrs.module.ModuleUtil.refreshApplicationContext(ModuleUtil.java:885) org.openmrs.module.web.WebModuleUtil.refreshWAC(WebModuleUtil.java:866) org.openmrs.module.web.controller.ModuleListController.onSubmit(ModuleListController.java:190) org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:274) org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:275) org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:146) org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:50) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868) javax.servlet.http.HttpServlet.service(HttpServlet.java:646) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) javax.servlet.http.HttpServlet.service(HttpServlet.java:727) org.openmrs.module.web.filter.ForcePasswordChangeFilter.doFilter(ForcePasswordChangeFilter.java:60) org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:72) org.openmrs.module.owa.filter.OwaFilter.doFilter(OwaFilter.java:57) org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:70) org.openmrs.module.web.filter.ModuleFilter.doFilter(ModuleFilter.java:54) org.openmrs.web.filter.OpenmrsFilter.doFilterInternal(OpenmrsFilter.java:108) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:150) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105) org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105) org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

root cause

java.lang.ClassNotFoundException: org.openmrs.module.addresshierarchy.AddressField
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1719)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1570)
org.openmrs.module.ModuleClassLoader.loadClass(ModuleClassLoader.java:563)
java.lang.ClassLoader.loadClass(ClassLoader.java:357)
org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.HaitiAddressBundle.getAddressComponents(HaitiAddressBundle.java:22)
org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.AddressBundle.getAddressTemplate(AddressBundle.java:78)
org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.AddressBundle.installAddressTemplate(AddressBundle.java:66)
org.openmrs.module.haiticore.org.openmrs.module.haiticore.metadata.AddressBundle.installEveryTime(AddressBundle.java:41)
org.openmrs.module.metadatadeploy.bundle.VersionedMetadataBundle.install(VersionedMetadataBundle.java:30)
org.openmrs.module.metadatadeploy.api.impl.MetadataDeployServiceImpl.installBundle(MetadataDeployServiceImpl.java:111)
org.openmrs.module.metadatadeploy.api.impl.MetadataDeployServiceImpl.installBundle(MetadataDeployServiceImpl.java:81)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy370.installBundle(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy512.installBundle(Unknown Source)
org.openmrs.module.haiticore.HaitiCoreActivator.installMetadataBundles(HaitiCoreActivator.java:47)
org.openmrs.module.haiticore.HaitiCoreActivator.started(HaitiCoreActivator.java:33)
org.openmrs.module.ModuleUtil.refreshApplicationContext(ModuleUtil.java:885)
org.openmrs.module.web.WebModuleUtil.refreshWAC(WebModuleUtil.java:866)
org.openmrs.module.web.controller.ModuleListController.onSubmit(ModuleListController.java:190)
org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:274)
org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:275)
org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:146)
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:50)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
org.openmrs.module.web.filter.ForcePasswordChangeFilter.doFilter(ForcePasswordChangeFilter.java:60)
org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:72)
org.openmrs.module.owa.filter.OwaFilter.doFilter(OwaFilter.java:57)
org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:70)
org.openmrs.module.web.filter.ModuleFilter.doFilter(ModuleFilter.java:54)
org.openmrs.web.filter.OpenmrsFilter.doFilterInternal(OpenmrsFilter.java:108)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:150)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  1. I didn’t know if this was a good opportunity to introduce compatibility to the module. The next steps would be to load in forms. We may also want to load in the appropriate CIEL/PIH concepts when we load the forms.

Thanks, Craig

@craigappl as for the NoClassDefFoundError, do you have a require_module or aware_of_module section for addresshierarchy in your config.xml?

@craigappl, +1 to what @dkayiwa stated - we will need to add a dependency on addresshierarchy to haiticore in this file.

I should also mention that a bunch of work has recently been done in addresshierarchy to support loading an address hierarchy + template configuration from a configuration file (in xml format). I believe the work that was done to support this also had to overcome the differences in pre-2.0 and post-2.0 location of the AddressTemplate class, and added reflection to deal with this.

See recently merged commit here, and ticket here. @mksd FYI.

Mike

Correct, merged here: commit 1760536, and will hopefully get released as part of 2.11.

@craigappl, if you are interested in this feature, here is an AH configuration example: addressConfiguration.xml

Thanks @mseaton @mksd @dkayiwa!

@craigappl, I saw that you closed this pull request and plan to issue a new one, just ping me and I’ll take a look when it’s ready!

re: loading forms and concepts, that makes sense to me, though we don’t currently load forms nor concepts via metadata deploy–we generally use metadata sharing to load concepts, and our forms are loaded via some custom (but rather simply, if I recall) code. This may give us an opportunity to see if we want to rethink how to do this. How are you currently deploying your forms and concepts?

Also @ball because she may be interested in how this discussion progresses.

Take care, Mark

Thanks @mseaton and @dkayiwa that was the problem! @mogoodrich I just got the code working and submitted a new PR.

Cool, great… I should be able to look at this today.

Take care, Mark

Hi @mogoodrich and @ball,

We load our forms in our openmrs-module-isanteplus module activator using the htmlformentryservice.

All of our concepts are mapped to the CIEL dictionary, so we load the SQL file after iSantePlus has loaded. It would be great if we could automate this import as part of our distro process.

Craig

Craig,

Oh, great, we basically use the same method to load forms that you do, so that will work fine.

We use Metadata Sharing to load concepts, so it’s possible we could create some common metadata sharing bundles with the concepts on these forms, but that would require some co-ordination. We are not enamored with loading concepts via metadata sharing, but we don’t currently have a better way. Anyway, when we get to this point we’d need further discussion and should bring in @ball who handles most of our concept work here.

Also, one other question–I should have thought of this earlier, but currently our “PIH distro” is a standard set of modules, and we use it in multiple countries (though the only site outside of Haiti currently is a smaller instance in Liberia). I’ve now added Haiti Core into that distro, yet we don’t want the Haiti Address Hierarchy, etc, outside of Haiti.

What do you think about not installing the various elements automatically, like we currently do in the activator? Long-term we could set up some sort of configuration mechanism if need be, but in the short-term it would be quite easy to create utility methods that install the various metadata, and then call those methods from our “PIH Core” module and your “iSantePlus” activator… this would give us a level of granularity as well, if there is some Haiti metadata you want and we don’t want or vice-versa.

Take care, Mark

Hi Mark,

Your idea about change the haiticore module activator sounds good. Could you work on that task and I’ll follow suit in the iSantéPlus activator once I understand your example in PIHCore?

@ball, I’m working through the registration process and am creating a list of concepts that aren’t mapped to the CIEL dictionary. I’m also keeping a list of items that do map to CIEL and hope we can get those into OCL.

Thanks, Craig