Wiki Spaces

Documentation
Projects
Resources

Get Help from Others

Q&A: Ask OpenMRS
Discussion: OpenMRS Talk
Real-Time: IRC Chat | Slack

Documentation

Page tree
Skip to end of metadata
Go to start of metadata

The following steps were outlined by Tammy Dugan on the developers' mailing list.

The following should be the complete solution for extending an OpenMRS table through a module:

  • add appropriate code in sqldiff.xml (or liquibase.xml, for more info see : https://wiki.openmrs.org/display/docs/Module+liquibase+File ) to add the column to the table
  • add an entry for the module's Encounter.hbm file under mappingFiles in config.xml
  • create an empty service to call the module's encounter that extends OpenMRS's EncounterService object
  • create an hbm file for the module's encounter with the following mapping format
    <hibernate-mapping auto-import="false">
        <subclass name="org.openmrs.module.atdproducer.Encounter"
                extends="org.openmrs.Encounter" discriminator-value="not null">
            <property name="scheduledTime" type="java.util.Date"
                    column="scheduled_datetime"/>
        </subclass>
    </hibernate-mapping>
    
    For this hbm file to work, the following xml must exist in the OpenMRS Encounter.hbm file:
    <discriminator column="encounter_id" insert="false" />
    

If this xml does not exist in the OpenMRS Encounter.hbm file, you will need to add it and create a custom build of OpenMRS.

  • create an encounter class that extends the OpenMRS encounter class.

Make sure to override the constructors from the super class and add getters, setters, and instance variables for the columns you are adding.

  • create an empty EncounterDAO class that extends OpenMRS EncounterDAO
  • create an EncounterServiceImp class that extends OpenMRS EncounterServiceImp and implements your module's EncounterService class.

Create an empty parameter constructor and create a method like the following:

public void setTestDAO(org.openmrs.module.atdproducer.db.EncounterDAO dao){
        this.dao = dao;
        super.setEncounterDAO(this.dao);
}

The method name should match the property xml wrapped around the hibernate implementation class in the moduleApplicationContext.xml file. Mine looks like this:<property name="testDAO">

  • add an entry in moduleApplicationContext just like you would for any other service and point to your service interface class, service implementation class, and hibernate implementation class for the added columns.
  • create a HibernateEncounterDAO that extends OpenMRS's HibernateEncounterDAO and implements your module's EncounterDAO. Create an empty constructor and a method that looks like the following:
    public void setSessionFactory(SessionFactory sessionFactory) {
            this.sessionFactory = sessionFactory;
            super.setSessionFactory(this.sessionFactory);
    }
    
    To make sure you return the correct type of encounter objects when you call your empty EncounterService class, you must override every method in OpenMRS's HibernateEncounterDAO that returns Encounter objects and convert them to your encounter objects. Here is an example method:
    public Set<org.openmrs.Encounter> getEncounters(Patient who, Location where) {
            Set<org.openmrs.Encounter> openMRSEncounters = super.getEncounters(who,
                    where);
            return convertOpenMRSEncToModuleEnc(openMRSEncounters);
    }
    
    private Set<org.openmrs.Encounter> convertOpenMRSEncToModuleEnc(Set<org.openmrs.Encounter> openMRSEncounters)
    {
    Set<org.openmrs.Encounter> moduleEncounters = new HashSet<org.openmrs.Encounter>();
    
    for (org.openmrs.Encounter currOpenMRSEncounter&nbsp;: openMRSEncounters){            moduleEncounters.add(this.getEncounter(currOpenMRSEncounter
                        .getEncounterId()));        }
    return moduleEncounters;
    }
    

2 Comments

  1. Darius --

    Is this still up to date?  I don't think discriminators are required at all in our table-per-concrete-class model.  I don't think it's necessary to override all the POJO setters and getters because a Module encounter is still an OpenMRS encounter.  And instead of converting all OpenMRS encounters to Module encounters, I think all that's necessary is to have a utility getter/setter for each additional field that (a) does  the get/set in a try-catch block, or (b) checks to see if the encounter passed in isAssignableFrom Module encounter, and then does the right thing. 

    1. This describes how to completely override a class, e.g. it's not like the scenario where core has Order and you're adding MyModuleOrder, but rather the case where you want to completely replace the Encounter class with one with an extra column. (The descriminator is a hack that Ben added long ago to every one of our classes to support this.)

      I haven't ever actually done this, so I haven't thought about whether there's a better way.