I’m working on a module that depends on the Xforms module, and I’m running into a dependency problem—certain (but not all) calls to my module fail with the error that XformsService cannot be found.
XformsService is defined in xforms-api but not in xforms-omod. I have xforms-omod-4.3.5.jar loaded (as an omod). However xforms-api (I’m looking at xforms-api-4.3.5.jar) cannot be loaded as a module because it does not contain a config.xml.
How does XformsService ever become available to the OpenMRS system? This used to work with Xforms 4.3.1 but it doesn’t seem to work anymore; I’m wondering if something changed recently where modules switched from foo to foo-api/foo-omod (especially since the openmrs-sdk:install-module rule now seems to append “-omod” to the end of the module name)?
I think I’m just confused as to what the api/ directory is for. I looked at the module developer’s documentation but couldn’t find an explanation. If anyone could help out or point me at some relevant documentation that would be terrific. Many thanks!
I can’t see why one worked but not the other. You can see that I flailed around a bit trying to put the xforms-api jar into the modules directory, but that shouldn’t have made a difference, right?
And now the error is back. (It’s definitely intermittent, perhaps due to a race condition — I restarted OpenMRS and it went away again.)
org.openmrs.api.APIException: Service not found: interface org.openmrs.module.xforms.XformsService
at org.openmrs.api.context.ServiceContext.getService(ServiceContext.java:724)
at org.openmrs.api.context.Context.getService(Context.java:931)
at org.openmrs.module.xforms.aop.XformsConceptAdvisor.afterReturning(XformsConceptAdvisor.java:46)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:51)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy94.saveConcept(Unknown Source)
at org.openmrs.projectbuendia.webservices.rest.DbUtil.getConcept(DbUtil.java:54)
I haven’t looked inside an omod file for a long time, but the idea is that
your dependent module should not include any xforms jar files.
It needs to declare it requires xforms in its config.xml and the OpenMRS
class loader will give your module access to the already loaded jars that
come from the xforms omod.
You also need to make sure that your pom.xml references to the xforms
dependencies have scope “provided” so that the jars are not included in
your build.
This turned out to be the issue: there were two copies of the xforms-api jar present, so the XformsService interface existed twice (two different interfaces named org.openmrs.module.xforms.XformsService with different memory addresses). It would be great to document this pitfall somewhere; the behaviour was pretty mysterious, and all the many layers of AOP abstraction made it quite difficult to use the debugger to understand what was happening.