Skip to content
Simon Kelly edited this page Feb 5, 2015 · 3 revisions

CommCare 1.2 CaseXML Configuration

In order for CommCare applications to be truly scalable, three basic conditions need to exist.

  1. CommCare needs to be available as a single binary download for all deployments
  2. CommCare's site specific configurations need to be available in a modular external format (suites)
  3. CommCare's suite definitions need to be up-datable per deployment, and the CommCare binary needs to be able to update independent of the suite definitions.

This document outlines a proposal which provides the structure necessary for the configuration of a commcare application that is independent of modifications to the binary, along with some of the associated framework which will need to exist for that configuration to be workable.

Scope

An external configuration will need to be capable of controlling all essential aspects of the application, including what locale files will be used, what settings are available, etc. As such, this proposal will assume that CommCare and its configuration are the only providers of application specific data. All binary modules for JavaRosa necessary for CommCare will be assumed to be included and their configurations will not be handled by this guide.

CommCare applications have a few elements of a JR binary that they need to be able to control. Some of these are currently externalized, some of them need to have changes made to be able to be externalized. Proposals for the later group will be included in this document.

These elements are

  • Menu items
  • Presence of XForms on the device and registered with JR
  • Presence of Locale files which are present on the device and registered
  • Multimedia Resource Files
  • Necessary Preloaded classes for XForms
  • Structure of Entity Select Screens
  • Structure of Case Detail screens
  • Full/Main Menu Structure

Abstract Data Type Definitions

Resources

XForms, Locale Files, and the Suite Registration files that are used for externalization all share common traits.

  • External Definition (controlled by suite writers)
  • Need for versioning
  • Are parsed once retrieved, and then stored locally in a quick to use format
  • May rely on other resources

These files will be considered resources in the external framework. Resources are files which are made available in suites, and are retrieved, processed, and persisted in a processed form.

Resource file definitions are contained inside of suites, providing a unique resource identifier along with a set of possible locations for the file in increasing levels of locality (cache, local, remote).

Suites

A suite defines a set of resources and application behavior which is dependent on those resources. At a high level a suite generally resembles something akin to "BRAC Household Visit", containing the XForms for manipulating a household visit case, the menu options availabe in the suite menu

Suites (being resources) are parsed and persisted in a processed form on a device, a uniquely identified suite absolutely defines an abstract datatype rather than a particular file, although a suite should generally be uniquely and fully described by an XML definition.

Suites contain definitions for the following high level data types:

  • Resources
  • Entries
  • Views
  • Details
  • Menus

Entry

Entries define a concrete user-initiated form-entry action that can be performed in a suite, possibly including some form of entity (Case, Referral, etc). If entities are included, a detail definition can also be provided in order to configure what information is presented when those entities are selected.

View

View defines another user initiated form-entry action, one which displays an entity and its details.

Detail

Detail definitions provide the information about an entity which should be used as a guide for selecting it, essentially the structure of the current Entity Select screen.

Menu

Menu definitions provide a hint for the application about how user actions should be presented to users. These definitions are not guaranteed to be honored, but can generally be used to define the structure of simple menus.

Implementation Details

All of the datatypes described here will have a couple of concrete implementations. The most concrete implementation consists of the XML definition files which describe a suite. In addition to this implementation, there will be an internal definition for each datatype on the phone's RMS, along with the representation of the various resources (Locale files, etc). Maintaining an atomic definition for a module is one of the primary concerns of the system.

XML Definitions

The general definition of the datatypes in XML are as follows:

Text

Text nodes are used in multiple definitions to label text for an element. This is a surprisingly difficult operation, since the following are all use cases that need to be covered

  • Localized Strings
  • Strings pulled from data objects like Cases or Referrals
  • Raw Strings

Since all of these elements need to be supported, there is a fairly rich text definition capability which utilizes the XPath query language. The essential definition follows this format

<text>                     <!----------- Exactly one. Will be present wherever text can be defined. Contains a sequential list of string elements to be concatenated to form the text body.-->
    <xpath function="">   <!------------ 0 or More. An xpath function whose result is a string. References a data model if used in a context where one exists. -->
        <variable name=""/> <!------------ 0 or More. Variable for the localized string. Variable elements can support any child elements that <body> can. -->
    </xpath>
    <locale id="">         <!------------ 0 or More. A localized string. id can be referenced here or as a child-->
        <id/>              <!------------ At Most One. The id of the localized string (if not provided as an attribute -->
        <argument key=""/> <!------------ 0 or More. Arguments for the localized string. Key is optional. Arguments can support any child elements that <body> can. -->
    </locale>
</text>

Suite

<suite version="">

<resource/>                    <!----------- 0 or More -->
<media/>                       <!----------- 0 or More -->
<entry/>                       <!----------- 0 or More -->
<detail/>                      <!----------- 0 or More -->
<view/>                        <!----------- 0 or More -->
<menu/>                        <!----------- 0 or More -->

</suite>

Resource

Resource definitions are declarative. This means that upon completely installing a suite, the resource definition will be true. This mechanism allows for suites to define that remote resources should be cached or locally stored.

<resource id="" version=""> <!----------- A resource which needs to be present and managed for this suite to be functional. Version should be a monotonically increasing integer, type should be one of the set of (xform, locale, suite). -->
    <location authority="">          <!----------- At Least One. A location where this resource can be retrieved. -->
    </location>
</resource>

Individual resource types use this definition to describe themselves

<xform>
    <resource/>
</xform>

<locale language="">
    <resource/>
</locale>

<suite>
    <resource/>
</suite>

Media

Media resources are used to describe the location of media files which need to be present in the local context in order to properly function. These files are accessed using javarosa URI's in the format jr://media/. Each media declaration block defines a set of resource files against a relative local root.

<media path="">                          <!----------- path is an optional attribute -->
    <resource id="" version="">          <!----------- 1 or more -->
        <location authority="">          <!----------- At Least One. A location where this resource can be retrieved. -->
        </location>
    </resource>
</media>

The path defines a step on the URI so that the same filename can be used for different media files. For instance

<media path="en">
    <resource id="intro" version="1">
        <location authority="remote">./english/intro.mp3</location>
    </resource>
    <resource id="confirm" version="1">
        <location authority="remote">./english/confirm.mp3</location>
    </resource>
</media>

<media path="ak">
    <resource id="intro" version="1">
        <location authority="remote">./afrikaans/intro.mp3</location>
    </resource>
    <resource id="confirm" version="1">
        <location authority="remote">./afrikaans/confirm.mp3</location>
    </resource>
</media>

These resources would be available at their respective URIs:

  • jr://media/en/intro.mp3
  • jr://media/en/confirm.mp3
  • jr://media/ak/intro.mp3
  • jr://media/ak/confirm.mp3

Entry

<entry>                   
    <form/>               <!----------- Exactly One. Namespace of the form to be used for data entry -->
    <command id="">       <!----------- Exactly One. ID is for menus. -->
        <text/>           <!----------- Exactly One. Well formed text as defined above. -->
    </command>
    <entity>              <!----------- 0 or More. An entity request. If present, the device will ask for an entity to be selected by the user before the form entry session starts. Entities will be chosen in order, and each previously selected entity will be available by reference. -->
        <type/>           <!----------- Exactly One. The type of entity to be retrieved (Supported: case, referral, model) -->
        <reference/>      <!----------- At Most One. A reference title to be used if a model will be built. If not defined, defaults to the 'type' field.-->
        <details chooseSingle="">     <!----------- 0 or More. A detail definition used for selecting this entity. chooseSingle is one of (true/false) and determines whether CommCare should automatically select an item if there is only one choice -->
           <!-- For the following elements, either a raw detail block should be used as a child, or a previously defined detail block should be referenced by providing the appropriate id -->
           <short id=""/>
           <long id=""/>             <!------------- Optional -->
        </details>
    </entity>
</entry>

Detail

<detail id="">
    <title><text/></title>            
    <model>                                                  <!----------- At Most One. Contains a structured data model which will be used by text definitions -->
        <ARBITRARY reference="" field=""/>                   <!----------- 1 or More. An arbitrary XML element. reference is the reference ID of the entity defined above, field is a field of that entity. For example reference="the-case" field="case-id" -->
    </model>
    <filter>                                                 <!----------- At Most One. Defines a filter for what should be displayed in this detail list -->
        <raw function=""/>                                   <!----------- At Most One. Defines a raw xpath function against the model defined which will include the entity if the function is equal to true, and exclude it if the function is equal to false -->
        <case case-type="" view-closed=""/>                  <!----------- Filters entities by the case associated with them. case-type is the case type of cases which should be included. View closed is 'true' if the filter should include closed cases, and 'false' otherwise. IF view-closed is not included, it will be assumed to be false -->
        <referral referral-type="" view-resolved=""/>        <!----------- Filters entities by the referral associated with them. referral-type is the referral type of the referrals which should be included. View resolved is 'true' if the filter should include referrals which are resolved, and 'false' otherwise. IF view-resolved is not included, it will be assumed to be false -->
    </filter>
    <field sortkey="">                                       <!----------- 1 or More. sortkey is one of (primary) and specifies the default sort order -->
        <header form="" width=""><text/></header>            <!----------- Exactly One. The header to be used to describe the field. Form is an optional hint which is one of (image, audio) which provides a hint for whether rich media should be displayed based on <text> returning a URI. Width is an optional hint for how much of the screen should be consumed by this field in percent with or without a % sign.-->
        <template form=""  width=""><text/></template>       <!----------- Same as above -->
    </field>
</detail>

Menu

<menu id="" root="">                       <!----------- id is a unique ID for this menu. if set to "root", the menu will attempt to be present at the root level. -->
    <text/>                                <!----------- 1. A well structured text for this menu. -->
    <command id=""/>                       <!----------- 0 or more. A list of commands which should be displayed on this menu. The commands will be presented in the order that they are defined here. -->
</detail>

Life Cycle

Since CommCare applications will depend on many suites, managing resources and suite definitions is vital. This section defines how CommCare will install, manage, and use Suites.

Information about this process is contained In the Usage Guide

Examples

This section contains sample definitions for CommCare applications in this framework.

Base Case

This is an extremely simple definition of an un-customized CommCare application which has standard operations for 4 xforms.

<suite version="1">

    <!-- Parse and cache the XForm -->
    <xform>
        <resource id="registration" version="1">
           <location authority="remote">./registration.xml
            </location>
        </resource>
    </xform>

    <!-- Parse and cache the XForm -->
    <xform>
        <resource id="followup" version="1">
           <location authority="remote">./followup.xml</location>
        </resource>
    </xform>

    <!-- Parse and cache the XForm -->
    <xform>
        <resource id="referral" version="1">
           <location authority="remote">./referral.xml</location>
        </resource>
    </xform>

    <!-- Parse and cache the XForm -->
    <xform>
        <resource id="brac_close" version="1">
           <location authority="remote">./brac_close.xml</location>
        </resource>
    </xform>

    <!-- Define entry actions for the forms -->
    <entry>                   
        <form>http://dev.commcarehq.org/SAMPLE/Registration</form>
        <command id="reg">
            <text>Register</text>
        </command>
    </entry>

    <entry>                   
        <form>http://dev.commcarehq.org/SAMPLE/Followup</form>
        <command id="followup">
            <text>Followup Visit</text>
        </command>
        <entity>
            <type>case</type>
            <reference>case</reference>
        </entity>
    </entry>

    <entry>                   
        <form>http://dev.commcarehq.org/SAMPLE/Referral</form>
        <command id="referral">
            <text>Complete Referral</text>
        </command>
        <entity>
            <type>case</type>
            <reference>case</reference>
        </entity>
        <entity>
            <type>referral</type>
            <reference>referral</reference>
        </entity>
    </entry>

    <entry>                   
        <form>http://dev.commcarehq.org/SAMPLE/Close</form>
        <command id="close">
            <text>Close Case</text>
        </command>
        <entity>
            <type>case</type>
            <reference>case</reference>
        </entity>
    </entry>
</suite>

Household Visit

This is what the household visit Suite would look like for CommCare BRAC in this framework.

<suite version="1">

    <!----------- Parse and cache the XForm -->
    <xform>
        <resource id="brac_registration" version="1">
           <location authority="remote">./brac_registration.xml</location>
        </resource>
    </xform>

    <!----------- Parse and cache the XForm -->
    <xform>
        <resource id="brac_followup" version="1">
           <location authority="remote">./brac_followup.xml</location>
        </resource>
    </xform>

    <!----------- Parse and cache the XForm -->
    <xform>
        <resource id="brac_referral" version="1">
           <location authority="remote">./referral_completed_form_chp.xml</location>
        </resource>
    </xform>

    <!----------- Parse and cache the XForm -->
    <xform>
        <resource id="brac_close" version="1">
           <location authority="remote">./brac_close.xml</location>
        </resource>
    </xform>

    <!----------- Read and locally store the translation strings-->
    <locale language="default">
        <resource id="brac_hh_strings_default" version="1">
           <location authority="local">jr://commcare/locale/messages_brac_hh_sw.txt</location>
           <location authority="remote">./messages_brac_hh_default.txt</location>
        </resource>
    </locale>

    <!----------- Read and locally store the translation strings-->
    <locale language="sw">
        <resource id="brac_hh_strings_sw" version="1">
           <location authority="local">jr://commcare/locale/messages_brac_hh_sw.txt</location>
           <location authority="remote">./messages_brac_hh_sw.txt</location>
        </resource>
    </locale>

    <!----------- Define the short detail model for household cases -->
    <detail id="hh_short">            
        <model>
            <data>
                <name reference="case" field="household_name"/>
                <houseid reference="case" field="external-id"/>
            </data>
        </model>
        <field>
            <header><text><locale id="hh.name"/></text></header>
            <template><text><xpath function="/data/name"/></text></template>
        </field>
        <field>
            <header><text><locale id="hh.id"/></text></header>
            <template><text><xpath function="/data/houseid"/></text></template>
        </field>
    </detail>

    <!----------- Define the long detail model for household cases -->
    <detail id="hh_long">            
        <model>
            <data>
                <name reference="case" field="household_name"/>
                <houseid reference="case" field="external-id"/>
                <date reference="case" field="date-opened"/>
                <status reference="case" field="status"/>
            </data>
        </model>
        <field>
            <header><text><locale id="hh.name"/></text></header>
            <template><text><xpath function="/data/name"/></text></template>
        </field>
        <field>
            <header><text><locale id="hh.id"/></text></header>
            <template><text><xpath function="/data/houseid"/></text></template>
        </field>
        <field>
            <header><text><locale id="hh.date.opened"/></text></header>
            <template><text><xpath function="/data/date"/></text></template>
        </field>
        <field>
            <header><text><locale id="hh.open"/></text></header>
            <template>
                <text>
                    <locale><id>
                        <xpath function="if(/data/status='open','standard.yes','standard.no'"/>
                    </id></locale>
                </text>
            </template>
        </field>
    </detail>

    <!----------- Define the short detail model for household referrals -->
    <detail id="hh_ref_short">            
        <model>
            <data>
                <houseid reference="case" field="external-id"/>
                <type reference="referral" field="type"/> 
                <date reference="referral" field="date-due"/>
            </data>
        </model>
        <field>
            <header><text><locale id="referral.header.hhid_short"/></text></header>
            <template><text><xpath function="/data/houseid"/></text></template>
        </field>
        <field>
            <header><text><locale id="referral.header.type"/></text></header>
            <template>
                <text><xpath function="if(/data/type = 'sickness', $sickness,
                                                                      if(/data/type = 'pregnancy_case', $pregnancy_case,
                                                                      if(/data/type = 'wound_case', $wound_case,
                                                                      if(/data/type = 'birth_registration', $birth_registration,
                                                                      if(/data/type = 'cc_case_pregnancy', $cc_pregnancy,
                                                                      '???')))))">
                                <variable name="sickness"><locale id="referral.type.sickness"/></variable>
                                <variable name="pregnancy_case"><locale id="referral.type.hh-pregnancy"/></variable>
                                <variable name="wound_case"><locale id="referral.type.wound"/></variable>
                                <variable name="birth_registration"><locale id="referral.type.birthreg"/></variable>
                                <variable name="cc_pregnancy"><locale id="referral.type.pregnancy"/></variable>
                          </xpath></text>
             </template>
        </field>
        <field>
            <header><text><locale id="referral.header.date"/></text></header>
            <template><text><xpath function="if(today() - date(/data/date) &lt;= 0,$today,
                                             if(today() - date(/data/date) &lt;= 1,$yesterday,
                                             format_date(date(/data/date),'short')))">
                                <variable name="today"><locale id="Today"/></variable>
                                <variable name="yesterday"><locale id="Yesterday"/></variable>
            </xpath></text></template>
        </field>
    </detail>

    <!----------- Define the long detail model for household cases -->
    <detail id="hh_ref_long">            
        <model>
            <data>
                <houseid reference="case" field="external-id"/>
                <name reference="case" field="household-name"/> 
                <type reference="referral" field="type"/> 
                <date-due reference="referral" field="date-due"/>
                <date-created reference="referral" field="date-created"/>
            </data>
        </model>
        <field>
            <header><text><locale id="referral.header.hhid_long"/></text></header>
            <template><text><xpath function="/data/houseid"/></text></template>
        </field>
        <field>
            <header><text><locale id="referral.header.type"/></text></header>
            <template>
                <text><xpath function="if(/data/type = 'sickness', $sickness,
                                                                      if(/data/type = 'pregnancy_case', $pregnancy_case,
                                                                      if(/data/type = 'wound_case', $wound_case,
                                                                      if(/data/type = 'birth_registration', $birth_registration,
                                                                      if(/data/type = 'cc_case_pregnancy', $cc_pregnancy,
                                                                      '???')))))">
                                <variable name="sickness"><locale id="referral.type.sickness"/></variable>
                                <variable name="pregnancy_case"><locale id="referral.type.hh-pregnancy"/></variable>
                                <variable name="wound_case"><locale id="referral.type.wound"/></variable>
                                <variable name="birth_registration"><locale id="referral.type.birthreg"/></variable>
                                <variable name="cc_pregnancy"><locale id="referral.type.pregnancy"/></variable>
                          </xpath></text>
             </template>
        </field>
        <field>
            <header><text><locale id="referral.header.name"/></text></header>
            <template><text><xpath function="/data/name"/></text></template>
        </field>
        <field>
            <header><text><locale id="referral.header.date"/></text></header>
            <template><text><xpath function="if(today() - date(/data/date-due) &lt;= 0,$today,
                                             if(today() - date(/data/date-due) &lt;= 1,$yesterday,
                                             format_date(date(/data/date-due),'short')))">
                                <variable name="today"><locale id="Today"/></variable>
                                <variable name="yesterday"><locale id="Yesterday"/></variable>
            </xpath></text></template>
        </field>
        <field>
            <header><text><locale id="referral.header.date"/></text></header>
            <template><text><xpath function="if(today() - date(/data/date-created) &lt;= 0,$today,
                                             if(today() - date(/data/date-created) &lt;= 1,$yesterday,
                                             format_date(date(/data/date-created),'short')))">
                                <variable name="today"><locale id="Today"/></variable>
                                <variable name="yesterday"><locale id="Yesterday"/></variable>
            </xpath></text></template>
        </field>
    </detail>

    <!----------- Define entry actions for Household Visit Cases -->
    <entry>                   
        <form>http://dev.commcarehq.org/BRAC/CHP/HomeVisit</form>
        <command id="hh-reg">
            <text><locale id="brac.hh.menu.reg"/></text>
        </command>
    </entry>

    <entry>                   
        <form>http://dev.commcarehq.org/BRAC/CHP/HomeVisit/Followup</form>
        <command id="hh-followup">
            <text><locale id="brac.hh.menu.followup"/></text>
        </command>
        <entity>
            <type>case</type>
            <reference>case</reference>
        </entity>
        <details type="short">
           <short id="hh_short"/>
           <long id="hh_long"/>
        </details>
    </entry>

    <entry>                   
        <form>http://dev.commcarehq.org/BRAC/CHP/HomeVisit/Referral</form>
        <command id="hh-referral">
            <text><locale id="brac.hh.menu.referral"/></text>
        </command>
        <entity>
            <type>case</type>
            <reference>case</reference>
        </entity>
        <entity>
            <type>referral</type>
            <reference>referral</reference>
        </entity>
        <details type="short">
           <short id="hh_ref_short"/>
           <long id="hh_ref_long"/>
        </details>
    </entry>

    <view>
        <command id="hh-view">
            <text><locale id="brac.hh.menu.view"/></text>
        </command>
        <entity>
            <type>case</type>
            <reference>case</reference>
        </entity>
        <details type="short">
           <short id="hh_short"/>
           <long id="hh_long"/>
        </details>
    </view>

    <entry>                   
        <form>http://dev.commcarehq.org/BRAC/CHP/HomeVisit/Close</form>
        <command id="hh-close">
            <text><locale id="brac.hh.menu.close"/></text>
        </command>
        <entity>
            <type>case</type>
            <reference>case</reference>
        </entity>
        <details type="short">
           <short id="hh_short"/>
           <long id="hh_long"/>
        </details>
    </entry>

</suite>
Clone this wiki locally