Write rule for data integrity module

@shivtej Where is the latest code so that I can help you from a review perspective.

To implement a test case you need to do the following:

  1. Setup your test class - like https://github.com/METS-Programme/openmrs-module-aijar/blob/1d9ccb3ca3aa5d2a33c9cd5ef89a7a4279ca57f8/api/src/test/java/org/openmrs/module/aijar/dataintegrity/IncompleteExposedInfantInformationTest.java

  2. You need a test data file - so that you can add data to show results from your tests. I tend to base from the openmrs one https://github.com/openmrs/openmrs-core/blob/master/api/src/test/resources/org/openmrs/include/standardTestDataset.xml

  • Setup a new patient with a date of death before date of birth
  1. When you run your rule it should return one patient, and can even check the patient’s ID

Setting up the tests will require you to run your test, find an error, fix it, run again etc … Its a step by step process and you will be the better for it. Once the tests run then we can look into adding your module to a Ref App SDK to deal with the UI stuff.

@ssmusoke , here you can find the code of the module using which I’m hosting data integrity rules: https://github.com/shivtej1505/ruleshost

@ssmusoke, I getting contextDAO is null error while writing test for dataintegrity rule. Here is full log: https://pastebin.com/MbXYnDWv .

You can see the test I wrote here and respective class here .

I also saw the FAQ here Unit Tests - Documentation - OpenMRS Wiki but I’m unable to solve this issue. Attaching surefire-report.

org.openmrs.module.ruleshost.dataintegrity.InvalidDateOfDeathTest.txt (7.5 KB)

@shivtej I think I may have misled you and which is causing all the confusion. So my suggestion is as follows:

  1. Create a new Reference Application Module
  2. Test Cases
  • Add a sample data file with a person whose death date is after the birth date - you may need to add dummy data for persons without death dates to ensure the rule ignores them
  • You do not need to mock anything in the test cases since they are very simple
  1. Add the Invalid Death Date rule
  • The criteria query you had was correct by the way - you just need to compare the death date to birth date
  • Once you get a list of patients you transform the list into the RuleResult

The approach is to write the tests first so that they fail - I cannot stress this enough I spent 4 weeks trying to work without tests, but took only 2 days with tests (I am evangelical about this)

@ssmusoke, I have successfully created test and tried on the sample rule. The rule is working fine, the test is passing. I request you to check the code I have written. You can access the test I wrote here and respective class here .

Thanks for pointing me at this approach. I learned lots of things. :slight_smile:

After successfully writing and testing the test, I tried to deploy the module in the server. The build was successful but both submodules (api and omod) was skipped. I’m not sure if it is a problem. I’m getting the same error (ui framework error) , here is the fresh log: https://pastebin.com/y7f4p2VB Please let me know about the next set of steps. Thanks.

@shivtej the getRule() method is what provides the metadata to save your rule to the database for running like https://github.com/METS-Programme/openmrs-module-aijar/blob/master/api/src/main/java/org/openmrs/module/aijar/dataintegrity/IncompleteARTInformation.java#L116-L125 so you need to add it to be able to see it

@ssmusoke, I updated the getRule method and again tried deploying it on the server. I’m still not able to see the rules if they aren’t in database. I guess I need to write unit test of getRule also. I’ve updated the source code accordingly, you can see it on the same repo.

Thanks

  1. The tests do not run, please remove everything that is not connected with Data integrity rules - such as RulesHostConfig, tests for DAOs etc.

  2. Add a requirement on data integrity module in the config.xml file

Thanks @ssmusoke for your help and patience. I think we are very close to our target. I’ve made the some changes including the changes you suggested. Now, the test is passing. I also dig through some DINT module code and understand the flow a little bit. I’m guessing, that the error (that UI error) is preventing us to saving the rule in the metadata.

I again tried to running server with DINT module and my custom module. I’m getting error in this block of [code] (openmrs-module-dataintegrity/RuleDefinitionLoader.java at master · openmrs/openmrs-module-dataintegrity · GitHub) . Java isn’t able to cast the loaded class into RuleDefinition class even the InvalidDateOfDeath implement this interface.

I request you to review my progress. I’ve updated the code of custom module. And here is my config.xml which I’m using in root folder of DINT module. config.xml (1.8 KB)

Please let me know if something is wrong. Thanks

I still cannot build your project locally, the test errors are initializationError(org.openmrs.module.ruleshost.api.dao.RuleshostDaoTest): org/springframework/core/annotation/AnnotatedElementUtils initializationError(org.openmrs.module.ruleshost.dataintegrity.InvalidDateOfDeathTest): org/springframework/core/annotation/AnnotatedElementUtils

  1. You do not need the test in RulesHostDaoTest
  2. I am using Oracle JDK fails on both 7 and 8 - how are you able to build the module?

@ssmusoke, I removed all the tests except ‘InvalidDateOfDeathTest’ from the source code. Your local repo might not be updated. I’ve pushed all the changed in this repo: https://github.com/shivtej1505/ruleshost .

I also faced similar problem when I was using Java 8 with spring 3 version. I switched to java 7 and then it got built successfully. I read somewhere all spring modules should have same version and java 8 isn’t compatible with spring 3.

@ssmusoke, I think I might be doing some mistake during deployment. Below are the steps I’m following:

  1. Run mvn clean install to generate .omod file.
  2. Copy the .omod file to module folder of the openmrs server. ( or mvn openmrs-sdk:deploy -DserverId=server )
  3. Start the server.

Please let me know if there is some problem with the steps.

  1. I was able to run the project in a Reference Application 2.6 Server - however I did not see the rules since the data integrity module is not included

  2. Download it from https://modules.openmrs.org/#/show/32/dataintegrity and add it to the server which is in $HOME/openmrs/serverId

  3. Stop your server and start it again

Tips:

  1. You should add your module to be watched by your server by typing mvn opnemrs-sdk:watch -DserverId=server in your module so that whenever you start a new server the module is compiled and deployed

  2. It will also enable auto reloading of UI components so you do not have to redeploy the module to see UI changes

@ssmusoke, I followed the exact steps you wrote but now I’m getting a new error, the server can’t find RuleDefinition class. Here is the log file: https://pastebin.com/Mz05friW

You need to require the data integrity module in your config.xml

@ssmusoke, I followed exact steps you told over the skype call. Hopefully I’m not getting that NoClassFoundError and InvalidCast error but now I’m getting another error. I tried different versions of hibernate but no luck.

UI Framework Error
Root Error

java.lang.NoSuchMethodError: org.hibernate.SessionFactory.getCurrentSession()Lorg/hibernate/classic/Session;
at org.openmrs.module.lite.dataintegrity.InvalidDateOfDeath.evaluate(InvalidDateOfDeath.java:22)
at org.openmrs.module.dataintegrity.rule.impl.DataIntegrityEvaluationServiceImpl.fireRules(DataIntegrityEvaluationServiceImpl.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy198.fireRules(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.openmrs.aop.LoggingAdvice.invoke(LoggingAdvice.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy199.fireRules(Unknown Source)
at org.openmrs.module.dataintegrity.page.controller.ResultsPageController.get(ResultsPageController.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.openmrs.ui.framework.UiFrameworkUtil.invokeMethodWithArguments(UiFrameworkUtil.java:112)
at org.openmrs.ui.framework.UiFrameworkUtil.executeControllerMethod(UiFrameworkUtil.java:71)
at org.openmrs.ui.framework.page.PageFactory.handleRequestWithController(PageFactory.java:219)
at org.openmrs.ui.framework.page.PageFactory.processThisFragment(PageFactory.java:160)
at org.openmrs.ui.framework.page.PageFactory.process(PageFactory.java:116)
at org.openmrs.ui.framework.page.PageFactory.handle(PageFactory.java:86)
at org.openmrs.module.uiframework.PageController.handlePath(PageController.java:116)
at org.openmrs.module.uiframework.PageController.handleUrlWithDotPage(PageController.java:83)
at sun.reflect.GeneratedMethodAccessor577.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:177)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.openmrs.module.web.filter.ForcePasswordChangeFilter.doFilter(ForcePasswordChangeFilter.java:60)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:72)
at org.openmrs.module.owa.filter.OwaFilter.doFilter(OwaFilter.java:57)
at org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:70)
at org.openmrs.module.web.filter.ModuleFilter.doFilter(ModuleFilter.java:54)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.openmrs.web.filter.OpenmrsFilter.doFilterInternal(OpenmrsFilter.java:108)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at   org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:150)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)

@shivtej You have not updated your code repository so I cannot review the latest code to advise.

Also for the tickets to work on focus on the ones documented on the GSOC project page https://wiki.openmrs.org/display/projects/Data+Integrity+Module+4.x+Improvement+Project

@ssmusoke, I have created a new module hosted here: https://github.com/shivtej1505/lite And I just wanted to start with small tickets to familiarize myself with the codebase but I think I have understood it decent enough by trying to setting it up.

@ssmusoke, did the custom module run fine on your system ?

I’m able to setup the data integrity module on my local machine. Relevant code can be found here: https://github.com/shivtej1505/lite

Anyone who is facing similar issue, pay special attention to config.xml and moduleApplicationContext.xml files.