Dashboard > DHIS Core Module > Home > DHIS Core development
  DHIS Core Module Log In | Sign Up   View a printable version of the current page.  
  DHIS Core development
Added by krin, last edited by margrsto on Nov 03, 2006  (view change)
Labels: 
(None)

DHIS Core development

The DHIS Core is under constant development, so the information in this document might be out of date. This is an attempt to give an overview over the different parts of the DHIS Core and how to use it. It will be a kind of summary of the information shared on the development mailing list.

If you have any questions about the information in this document, send an email to the development list. Please feel free to correct any spelling mistakes etc.

DHIS Core version

This document refers to the newest development branch of DHIS Core. At the time of writing this was Milestone 1.
Information on how to convert from alpha-1 to M1 can be found in the convertion guide

Index

General

Some general info:

  • All interfaces in the DHIS API have a public static member called ID, which contains the full class name of the interface. The full class name is used as bean ID's for having a consistent naming scheme and making it easier to request beans. (E.g. you will always know the bean id: Interface.ID).
  • All beans configuration files should be named beans.xml and be located in src/main/resources/META-INF/dhis/
  • DHIS Core follows (or should follow) the guidelines in the DHIS code conventions document.

The structure

The DHIS Core consists of several projects, structured and named after their purpose.

  • dhis-api (org.hisp.dhis.*)
    This is the API of the DHIS Core, consisting of all interfaces, value objects and exception classes.
  • dhis-core (org.hisp.dhis.*)
    The dhis-core project consist of all the "non-specific" implementations of interfaces in the API. Implementations that are common to all projects that will use the DHIS Core projects.
  • dhis-services (org.hisp.dhis.service.*)
    • dhis-service-datastore-hibernate (org.hisp.dhis.service.datastore.hibernate.*)
      This project contains the Hibernate v.3 implementation of org.hisp.dhis.service.datastore.DataStore.
    • dhis-service-organisationstore-hibernate (org.hisp.dhis.service.organisationstore.hibernate.*)
      This project contains the Hibernate v.3 implementations of org.hisp.dhis.service.organisationstore.OrganisationStore.
    • dhis-service-validation-hibernate (org.hisp.dhis.service.validation.hibernate.*)
      This project contains the Hibernate v.3 implementations of org.hisp.dhis.service.validation.ValidationStore.
  • dhis-support (org.hisp.dhis.*)
    • dhis-support-hibernate (org.hisp.dhis.*)
      The dhis-support-hibernate project consist of classes that makes it easier to work with Hibernate in your projects. Eg. a session manager and a transaction manager.
    • dhis-support-test (org.hisp.dhis.*)
      This project have classes for making it easier to do unit testing with JUnit in your project.
    • dhis-support-transaction
    • dhis-support-webwork (org.hisp.dhis.transaction.webwork.*)
      At the moment, the dhis-support-webwork project only have a transaction interceptor for WebWork.

Overview of the DHIS Core

This section will try to give an overview of the most important parts of the DHIS Core, how to use it, and why.

The DataStore

org.hisp.dhis.service.DataStore

This interface deals with the data elements and its related types. We are trying to create a data store that is as general as possible, and not specifically tied to health data. This component should be able to register values of any kind of DataElement, at a given time, tied to a registration source (in our case an OrganisationUnit). The component contains five value objects:

  • PeriodType - Definition of any kind of time period (eg. monthly, weekly, yearly).
  • Period - A time period defined with a PeriodType, a start date, and an end date.
  • DataElement - One data element, of any kind.
  • DataValue - A registered value of a DataElement, associated with a Period and a source. Source can be anything, in our case an OrganisationUnit.
  • DataElementGroup - A group of DataElements, can be any kind of user defined grouping.

The DataStore treats all the different kinds of DataElements as the same. Registered values of routine-, survey-, or semi-permanent data elements are all stored as DataValues. The only difference is the 'flag' member of the DataValue class, used to specify what kind of data is registered (routine-, survey-, or semi-permanent data values).

None of the projects in DHIS 2 is supposed to use the DataStore interface directly, but should use the interfaces that lie "above". This has been done in order to make it easier for the bridge module to create alternative implementations that work with the 1.3 or 1.4 database versions, and to make it easier to change the different parts of the DataStore.

A Hibernate implementation of the DataStore interface is in place, located in the dhis-service-datastore-hibernate project.

org.hisp.dhis.service.datastore.dataelement.DataElementStore

This is the first of the five interfaces that lie "above" the DataStore. It deals with basic CRUD (Create Read Update Delete) of DataElements and DataElementGroups. An implementation of this interface is in the dhis-core project, called org.hisp.dhis.service.datastore.dataelement.DefaultDataElementStore.

org.hisp.dhis.service.datastore.period.PeriodStore

This interface deals with Periods and PeriodTypes, usually the implementation of this interface will use the DataStore (as with DataElementStore). An implementation of this interface is in the dhis-core project, called org.hisp.dhis.service.datastore.period.DefaultPeriodStore.

org.hisp.dhis.service.datastore.routine.RoutineDataStore

This interface handles CRUD operations for routine data values. You will find an implementation of this interface in the dhis-core project, called org.hisp.dhis.service.datastore.routine.DefaultRoutineDataStore. This implementation will take care of setting the 'flag' member of the DataValue (as mentioned above), to mark it as a routine data value.

org.hisp.dhis.service.datastore.semipermanent.SemiPermanentDataStore

This interface is basically the same as RoutineDataStore, but for working with semi permanent data values. You will find an implementation of this interface in dhis-core, called org.hisp.dhis.service.datastore.semipermanent.DefaultSemiPermanentDataStore.

org.hisp.dhis.service.datastore.survey.SurveyDataStore

Not yet created.

Default implementations ++

dhis-core

In the dhis-core you will find all the common or default implementations, meaning implementations of the interfaces that don't have "product specific implementations" (eg. the Hibernate implementation of DataStore - HibernateDataStore). These implementations are usually called Default*. These implementations usually depend on other interfaces that have "product specific implementations". E.g. DefaultRoutineDataStore has a dependency on a DataStore. Because of this, we created the dhis-api-test project, with in-memory implementations of the interfaces that the interfaces in dhis-core depend on, to make it easier to switch implementations and to get a more sane dependency list.

org.hisp.dhis.transaction.*

dhis-core has a transaction interceptor, called TransactionInterceptor. This interceptor is set up with a transaction manager (eg. HibernateTransactionManager, and I know the bridge module has a JDBCTransactionManager), and can be used to intercept all method calls for an interface, making sure that the thread runs inside a transaction.

Example: Setting up a bean with a the TransactionInterceptor
<beans>
  <bean id="org.hisp.dhis.service.datastore.DataStore"
        class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target">
      <bean id="target"
            class="org.hisp.dhis.service.datastore.hibernate.HibernateDataStore">
        <property name="sessionManager">
          <ref bean="org.hisp.dhis.hibernate.HibernateSessionManager"/>
        </property>
      </bean>
    </property>
    <property name="proxyInterfaces">
      <value>org.hisp.dhis.service.datastore.DataStore</value>
    </property>
    <property name="interceptorNames">
      <list>
        <value>transactionInterceptor</value>
      </list>
    </property>
  </bean>
</beans>

OrganisationUnits

org.hisp.dhis.service.organisation.OrganisationStore

This component deals with the structuring of organisational units. Supporting hierarchical structuring of organisational units and grouping. This component has two value objects:

  • OrganisationUnit - Represents one organisational unit, with parent and child associations for the hiererchical structuring.
  • OrganisationUnitGroup - Defines a group of OrganisationUnits and includes a set for the associations.

The interface called OrganisationStore defines how to work with these value objects. There's currently a discussion about how we are going to deal with changes to the OrganisationUnit hierarchy. We need some kind of way for storing the history when we move an OrganisationUnit in the hierarchy (change the parent), and retrieve this history when we need to do queries on the data stored in the period when the OrganisationUnit was moved.

Validation (!!! THIS MODULE IS CURRENTLY UNDER REFACTORING !!!)

The validation part of DHIS 2 is seperated into two parts - defining which validation rules should be applied to the different elements, as well as actually validating the elements.

org.hisp.dhis.service.validation.ValidationStore

We need to be able to define validation rules for:

  • DataElement - standards for everybody

This interface deals with CRUD operations for validators. It stores these value objects:

  • DataElementValidation - Associating one validator (with the context) with one DataElement.

The naming of these classes might be a little difficult to comprehend. E.g. you would never actually validate a DataElement, since a DataElement is only a definition of something you register. That is, you validate a value, with no other reference than the DataElement. DataElementValidation means a validation rule applied to a DataElement and nothing else. A DataElementValidation is a way of specifying that a validation rule should apply for anyone using that DataElement. Examples of this later.

Example: Storing a DataElementValidation with a MinMaxValidator
int dataElementId = dataStore.addDataElement( "name", "description", true, DataStore.INT );

String minMaxValidator = "org.hisp.dhis.service.validation.MinMaxValidator";

Map context = new HashMap();
context.put( "min", "0" );
context.put( "max", "100" );

validationStore.addDataElementValidation( dataElementId, minMaxValidator , context );

org.hisp.dhis.service.validation.ValidationManager

This is the interface for doing validation on the different elements. It currently only supports validation of DataElements and FormElements (FormElementTemplates are never validated). The definitions of the validation rules for the different elements are hidden from the user, and if you only need to do validation, then you only need to deal with this interface.

The support projects

A set of projects aiming to make the life of DHIS developers easier.

dhis-support-hibernate

org.hisp.dhis.hibernate.*

With the Hibernate session manager (configured as a bean with id="org.hisp.dhis.hibernate.HibernateSessionManager") you can get the current session for the thread. It will also set up your Hibernate configuration. Properties can be added and overridden in an optional hibernate.properties file in your classpath.

Example: Using a HibernateSessionManager
private HibernateSessionManager sessionManager;

// ----------------------------------------------------------------------
// Dependency Setters
// ----------------------------------------------------------------------

public void setSessionManager( HibernateSessionManager sessionManager )
{
    this.sessionManager = sessionManager;
}

...

// ----------------------------------------------------------------------
// DataElement
// ----------------------------------------------------------------------

public int addDataElement( String name, String description, boolean active, String type )
    throws DataStoreException
{
    DataElement dataElement = new DataElement( name, description, active, type );

    try
    {
        Session session = sessionManager.getCurrentSession();

        Integer id = (Integer) session.save( dataElement );

        return id.intValue();
    }
    catch ( HibernateException ex )

    {
        throw new DataStoreException( "Failed to add data element", ex );
    }
}

org.hisp.dhis.transaction.*

With the transaction manager (configured as a bean with id="org.hisp.dhis.transaction.TransactionManager") you can manually wrap several method invocations in one transaction. Convenient for example when you are doing unit testing (to avoid lazy loading issues). The transaction manager is also used in the TransactionInterceptor (located in dhis-core, look at one of the hibernate implementation project's beans.xml for how to set it up), and in the WebWorkTransactionInterceptor (more about this later).

Example: Using a TransactionManager
// taken from HibernateValidationStoreTest

// Without using the transactionManager, this would have resulted in a lazy initialization exception,
// since the context (Map) is lazy loaded, like all of the collections in DHIS 2.
transactionManager.enter();
assertTrue( validationStore.getDataElementValidation( dataElementId, validator1 )
        .getContext().get( "min" ).equals( "0" ) );
transactionManager.leave();

dhis-support-test

This project has mainly one interesting class, org.hisp.dhis.DhisSpringTest. This class will go through your classpath, looking for META-INF/dhis/beans.xml files, and combine them into one XmlApplicationContext. It provides the convenience methods getBean( String id ) / getBean( String id, Class clazz), that you can use to get your beans from the application context. Extend this class in your test classes, and override the methods setUpTest() and tearDownTest() (these will be run by DhisSpringTest's setUp() and tearDown(). Set up your beans in setUpTest().

dhis-support-webwork

This project only contains the WebWorkTransactionInterceptor, used to wrap your WebWork action in one transaction.

Example: web.xml with a WebWorkTransactionInterceptor
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN"
   "http://www.opensymphony.com/xwork/xwork-1.0.dtd">

<xwork>

 <include file="webwork-default.xml"/>

 <package name="default" extends="webwork-default">
   <default-interceptor-ref name="defaultStack"/>

   <interceptors>
     <interceptor name="transactionInterceptor"
         class="org.hisp.dhis.transaction.webwork.WebWorkTransactionInterceptor"/>
     <interceptor-stack name="transactionInterceptedStack">
       <interceptor-ref name="defaultStack"/>
       <interceptor-ref name="transactionInterceptor"/>
     </interceptor-stack>
   </interceptors>

   <action name="yourAction" class=".....YourAction">
     <result name="error" type="dispatcher">index.html</result>
     <result name="success" type="velocity">success.vm</result>
     <interceptor-ref name="transactionInterceptedStack"/>
   </action>

 </package>

</xwork>

Using the DHIS Core

Getting the source code and getting started

Information about getting the source code and getting started can be found at the [development support page].

The DHIS Core projects can be found in the scm/trunk/dhis-2 directory.

After installing the necessary artifacts (built projects -> jars) into your local repository and declared the necassary dependencies in your Maven POM, you can access the DHIS Core beans in your application. For this to be possible, you have to read the beans configuration files of your dependencies and combine them into one ApplicationContext. In the DHIS Core we do this in two ways:

In your java code, you can do it like this (you can see how this is done in the DhisSpringTest class, in dhis-support-test):

Example: Combining the beans.xml files into one ApplicationContext
...
ClassPathXmlApplicationContext context;

String[] locations = {
    "classpath*:/META-INF/dhis/beans.xml",
};

context = new ClassPathXmlApplicationContext( locations );
...

In WebWork, you need to set up your web.xml file, so that it will look for the configured actions in your Spring beans configuration.

Example: web.xml set up with xwork-optional
<web-app>
  <display-name>My Webwork Application</display-name>

    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
        classpath*:/META-INF/dhis/beans.xml
      </param-value>
    </context-param>

    <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
      <listener-class>
        com.opensymphony.xwork.spring.SpringObjectFactoryListener
      </listener-class>
    </listener>
    ...

In your xwork.xml file, you must use the bean IDs as the class names of your actions.

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.6 Build:#812 Aug 06, 2007) - Bug/feature request - Contact Administrators