Extending a Table Through a Module

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://openmrs.atlassian.net/wiki/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;
    }