ADA Documentation

This is documentation for ART-DECOR Release 2 and tends to be out-dated. Please visit our new documentation site at docs.art-decor.org

This chapter contains the documentation of ART DECOR Applications (ADA), for those who want to start building and deploying ADA apps. ADA apps are fully functional applications, generated from DECOR datasets, transactions and valueSets.

ADA is an ideal tool for:

  • rapid prototyping, to show care providers what the DECOR specs functionally mean;
  • iterative improvement of DECOR specs, where feedback on the ADA app is used to improve the DECOR specs;
  • creating realistic examples, since care providers themselves can provide those using ADA,
  • to make examples in a simplified XML format, to be used as the basis for conversion to HL7 or other formats.

ADA is not:

  • secure, so never use real patient data in ADA;
  • a complete application (i.e. there is no database with patient data from which to start, one tests only transactions);
  • a UI with the capabilities of a tailor-made interface - the focus is on functional completeness, not necessarily the optimal workflow for a real-life scenario.

Installing ADA

To get started with the examples, you'll need ADA Core checked out to a local directory. Either get it from SourceForge, or install the ADA package in eXist and copy that to disk.

Start with this layout. Installing the ADA package will take care of most of this (not my-project, but it does the rest):

 - ada
   - core (for ada/core)
 - ada-data
   - projects
     - my-project (we'll use demo1 in this Guide)
       - definitions
       - new
       - schemas
       - views

After downloading ADA, ada-data/projects/empty contains the layout to get you started.

ADA Applications

ADA starts with a DECOR release, as made in the ART project form. Make one (or refer to an existing one), and retrieve the URI to it through: http://localhost:8877/decor/services/ProjectIndex (Throughout this Guide, we'll use localhost:8877 for the host - use another if you don't run a local instance on port 8877). Search for your project, and get an URL like this one: http://localhost:8877/decor/services/RetrieveTransaction?id=2.16.840.1.113883.3.1937.99.62.3.4.2&language=en-US&version=2014-05-12T14:02:55&format=xml

With RetrieveTransaction, a decor/transaction is 'enhanced' with all the goodies the dataset and terminology provide. It is:

  • a decor transaction
  • with the tree view from the dataset
  • all concept adornments (names, valueDomains, you name it) from the dataset
  • for every valueDomain of type 'code', the relevant valueSet pulled in
  • and all this filtered for just one particular language so you don't need to worry about stuff you don't need to worry about.

ADA Definitions

Now make an ADA definition file in /projects/my-project/definitions and call it demoapp-ada.xml. Here's an overview of the structure.

Note: if you want a generated start point for your project, or this demo project, please go to /decor/services/RetrieveProject?prefix=demo1- on your server. Select your project, select your version (if any), and using mode 'ada-definition' you may generate a definition as outlined below.

<?xml version="1.0" encoding="UTF-8"?>
<ada xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:noNamespaceSchemaLocation="../../../core/ada.xsd">
    <project prefix="demo1-" language="en-US" 
        versionDate="...">
        <release baseUri="http://localhost:8877/decor/services/RetrieveTransaction"/>
    </project>
    <applications>
        <application version="1">
            <views>
                <view id="1" type="crud" target="xforms" 
                    transactionId="..." 
                    transactionEffectiveDate="...">
                    <name>My Form</name>
                    <concepts include="all"/>
                </view>
                <view id="2" type="index" target="xforms" 
                    transactionId="..." 
                    transactionEffectiveDate="...">
                    <name>My Index</name>
                    <indexOf ref="1"/>
                    <concepts include="only"/>
                </view>
            </views>
        </application>
    </applications>
</ada>

The root is called /ada, below are:

project

<project prefix="demo1-" language="en-US" versionDate="2014-05-12T14:02:55">
     <release baseUri="http://localhost:8877/decor/services/RetrieveTransaction"/>
</project>

Change the following:

  • set project/@prefix to your project prefix (for documentation only)
  • set project/@language to the language from the RetrieveTransaction link
  • set project/@versionDate to the date from the RetrieveTransaction link (leaving it empty will retrieve the 'live' version of the transaction)

ADA retrieves all necessary information from the RetrieveTransaction service. Make sure this is OK (like, all names for the required language are provided, valueSets are present in the concepts etc.). If not all is present - ADA is a really good way to test the completeness of your DECOR specs. Just generate an ADA app, run it and see what's missing.

application

Next comes a bit of housekeeping.

<applications>
    <application version="1">
        <params>
            ...
        </params>
        <views>
            <view ...>
            </view>
        </views>
    </application>
</applications>

Everything except the application/@version this is just a way to get you to where it really happens: the view. An ADA view is - basically - an enhanced version of the RetrieveTransaction output, just like RetrieveTransaction itself is an enhanced version of a DECOR transaction. The ADA view allows you to add in UI necessities:

  • widgets
  • tabs
  • links between views (such as an index which points to detail views)
  • and more, and still more to come.

params

Sometimes you want to globally override certain behavior. Using a parameter you may override/extend certain behavior in creating the release file. You may define parameters at almost any level, but the parameter that is 'closest' to the item it needs to affect, counts. At present these options, depicted with their recommended settings, are supported here:

    <param name="overrideDatatypeDateTimeAsString" value="true"/>
    <param name="overrideDatatypeTextAsString" value="true"/>
    <param name="overrideContainsAsIdentifier" value="false"/>
  • overrideDatatypeDateTimeAsString - Using this parameter you can override valueDomain/@type='datetime', valueDomain/@type='date' as string. This supports forms that need parametrized dates which are not valid dates in itself. The only other way to do this is by listing and overriding each concept separately. Date or dateTime depends on the original valueDomain and properties in the dataset. Supported formats for parametrized dates in general are:
    • T = today
    • T-10D = ten days ago. Also support for M (months), or Y (years)
    • T+10D = ten days from today. Also support for M (months), or Y (years)
    • T-10D{hh:mm:ss} = ten days ago at exactly hh:mm:ss. No need to state seconds
    • T+10D{hh:mm:ss} = ten days from today at exactly hh:mm:ss. No need to state seconds
    • T{hh:mm:ss} = today at exactly hh:mm:ss. No need to state seconds
    • Stating a regular date as YYYY-MM-DD or dateTime as YYYY-MM-DDThh:mm:ss is also possible
  • overrideDatatypeTextAsString - Using this parameter you can override valueDomain/@type='text' as string. This supports forms that do not want rich text as value for the concept values. The only other way to do this is by listing and overriding each concept separately using valueDomainType='string'.
  • overrideContainsAsIdentifier - Using this parameter you can override concepts with a contains element, that do not have a valueDomain and are not marked for expansion somewhere to be an item with valueDomain/@type='identifier'. This supports referencing identified 'objects' that live somewhere else although undefined where , like health care provider or patient. The only other way to do this is by listing and overriding each concept separately.

view

Most of the times, you'll want two views:

  • a CRUD form for creating and editing data based on your transaction
  • an index form which lists and links to the created records.

The ADA view is where it all happens. Views need:

  • a view/@type (we'll use 'crud' and 'index' in this walkthrough)
  • a view/@target (for which we'll explore 'xforms' - html is another obvious candidate)
  • a view/@transactionId and view/@transactionEffectiveDate (this of course identifies the corresponding DECOR transaction)
  • an optional attribute view/@addComments. If 'true', group headers will have a 'comment' input control where the user can describe the group, particularly useful when ADA is used to make test cases.
  • an optional attribute view/@errorSummary (default 'true') which supresses the Orbeon error-summary. In large forms the error-summary may lead to runtime errors. Set to 'false' to suppress the Orbeon error-summary.
  • an optional attribute view/@language which overrides the project/@language.
  • a view/name (which is shown in the browser)
  • one or more view/concepts or (only for indexes) view/indexOf/concepts. concepts come in two flavors:
    • concepts include='all' (All concepts in the DECOR transaction are shown. No concept children are needed, unless you want special processing for those.)
    • concepts include='only' (No concepts in the DECOR transaction are shown, except the children of <concepts>.)
    • concept/@ref points to a DECOR concept from the DECOR transaction to override properties of and/or add concepts to as first in group or
    • concept/@preceding-ref points to a DECOR concept from the DECOR transaction to add contained concepts before or
    • concept/@following-ref points to a DECOR concept from the DECOR transaction to add contained concepts after
    • concept/@widget is used for UI specials (In this example, we'll create two tabs - of course, for a tabbed view, you might want to choose concepts groups on the same depth in the DECOR dataset tree.)
    • concept/@adaId is used to offer an @id on the concept in the ADA format. This @id is expected to behave like an xml:id / xs:ID. This concept/@id may subsequently be referred to by a concept[@datatype = 'reference']/@value

Note that if you are defining extra concepts, than these must be fully populated comparable to concepts in a compiled dataset.

This view will constitute the main CRUD view to edit or create instances of this particular transaction. The transaction below is a 'measurement form', where a patient can periodically submit weight measurements to a registry (the example is meant to show all main DECOR constructs, and is admittedly somewhat artificial). For CRUD forms, only 'xforms' is currently a valid target environment.

<view id="1" type="crud" target="xforms"
  transactionId="2.16.840.1.113883.3.1937.99.62.3.4.2"
  transactionEffectiveDate="2012-09-05T16:59:35">
    <name>Measurement Form</name>
    <concepts include="all">
        <concept ref="2.16.840.1.113883.3.1937.99.62.3.2.1" widget="collapse" 
          initial="open"  minimumMultiplicity="1"/>
        <concept ref="2.16.840.1.113883.3.1937.99.62.3.2.6" widget="collapse"/>
        <concept ref="2.16.840.1.113883.3.1937.99.62.3.2.3" widget="radio"/>
        <concept ref="2.16.840.1.113883.3.1937.99.62.3.2.5" widget="radio"
          default="4"/>
        <concept notPresentWhen="../weight_gain/@value='false'"
          ref="2.16.840.1.113883.3.1937.99.62.3.2.18"/>
    </concepts>
</view>

For index views the following options exist for specifying concepts that need to be in the index page:

  • view has @transactionId and <concepts/> has no @transactionId
    • Meaning: consider child concepts under <concepts> for @transactionId
<view id="1" type="index" target="xforms" transactionId="2.16.840.1.113883.3.1937.99.62.3.4.2"
    transactionEffectiveDate="2012-09-05T16:59:35">
    <name>Measurement Form</name>
    <concepts include="only">...</concepts>
</view>
  • view has no @transactionId and <concepts/> has @transactionId + @transactionEffectiveDate
    • Meaning: consider child concepts under <concepts> for @transactionId + @transactionEffectiveDate
<view id="1" type="index" target="xforms">
    <name>Measurement Form</name>
    <concepts include="only" transactionId="2.16.840.1.113883.3.1937.99.62.3.4.2"
        transactionEffectiveDate="2012-09-05T16:59:35">...</concepts>
</view>
  • view and concepts both have no @transactionId
    • Meaning: consider child concepts under <concepts> for all transactions in definition
<view id="1" type="index" target="xforms">
    <name>Measurement Form</name>
    <concepts include="only">...</concepts>
</view>
  • view has no @transactionId, there no view/concepts, indexOf contains <concepts>
    • Meaning: consider child concepts under <concepts> for the transaction that indexOf points to
<view id="1" type="index" target="xforms">
    <name>Measurement Form</name>
    <indexOf ref="2">
        <concepts include="only">...</concepts>
    </indexOf>
</view>
<view id="2" type="crud"  target="xforms" ... 
    transactionId="2.16.840.1.113883.3.1937.99.62.3.4.2" 
    transactionEffectiveDate="2012-09-05T16:59:35">
    ...
</view>

Views can define which widgets are used. They can also override DECOR attributes such as minimumMultiplicity in this example. If an attribute occurs in both the DECOR and ADA definitions, the ADA one will take precedence. This may be necessary when UI behaviour is not the same as the definition for messaging.

We'll make a second view, since we'll need an index of all weight measurements for lookups and edits. We'll list the concepts we want shown in the index (name and date of measurement, here). For indexes, 'xforms' is a valid target environment.

Take care:

  • use a unique name for the index, not the same name as the main form
  • indexes need an "indexOf" element which points to the @id of the form being indexed
<view id="2" type="index" target="xforms"
    transactionId="2.16.840.1.113883.3.1937.99.62.3.4.2" 
    transactionEffectiveDate="2012-09-05T16:59:35">
    <name>Measurement Index</name>
    <indexOf ref="1"/>
    <concepts include="only">
        <concept ref="2.16.840.1.113883.3.1937.99.62.3.2.4"/>
        <concept ref="2.16.840.1.113883.3.1937.99.62.3.2.2"/>
    </concepts>
</view>

concept children

Children from a concept in a view are copied as-is. This allows for:

  • The insertion of new concepts which are not in the dataset. Examples are: comments, displayNames etc. which are not required in the dataset but provide extra information in this view. Concept children should look like the XML output from RetrieveTransaction, with unique id's and names and shortNames which are unique in the context (i.e. no homonymous siblings). Provide at least: @id, @minimumMultiplicity, @maximumMultiplicity, @type, implementation/@shortName, name, valueDomain/@type.
  • Pieces of code, provided one uses a code generator which picks those up (the standard XForm code generator for ADA doesn't).
<concept ref="2.16.840.1.113883.3.1937.99.62.3.2.1">
    <concept id="test-01" minimumMultiplicity="1" maximumMultiplicity="1" type="item">
        <implementation shortName="test"/>
        <name>Test</name>
        <valueDomain type="string"/>
    </concept>
</concept>
<concept ref="2.16.840.1.113883.3.1937.99.62.3.2.6">
    <script>function(x, y) ....</script>
</concept>
</view>

UI attributes for concepts

Concepts may need extra data which is not part of the DECOR definition. but is solely there for the UI logic. These can be added to the concepts in the ADA definition.

UI attribute Example Description
default default="4" Provides a default value which is used instead of an empty value for newly added concepts. For codes this should be @localId when concepts have a valueSet, or else valueDomain/conceptList/concept/name.
notPresentWhen notPresentWhen="../weight_gain/@value='false'" Will not show the concept if the mentioned condition is true. The condition must be an XPath expression relative to the current concept in the ADA XML format.
widget See below.
initial initial='open' initial='closed' Initial state for collapsible widgets. 'closed' is the default.
skip skip="true", skip="1" This concept is skipped in the UI. The schema isn't changed, and the xml element corresponding to the skipped item is inserted in the ADA XML. Use with caution, since skipped concepts cannot be added, changed or removed in the UI. Skipping items is not recommended, since it may lead to invalid ADA XML data. Main use: skip superfluous group levels.
order order='1', order='2', order='99' Determines the order in which the concepts are shown in the UI. All concepts siblings must have an order number for this feature to work.
adaId adaId="true", adaId="false" (default value) Adds the option of a concept/@id in ADA instances that behaves like an xml:id / xs:ID

widgets

These are the currently supported widgets for each target platform.

Widget Target Description
tab XForms Will generate a tab for this concept (group). Use only on top level. When widget is not 'tab', groups will be collapsible.
radio XForms Will generate radio buttons for codes instead of a drop-down list.

Specifying UI attributes through ART DECOR

There's also a convenient route to specify UI attributes for ADA through ART. ART supports communities. In any project, in the project window, choose 'MyCommunity' and make a new community with name 'ada'. (DisplayName can be anything you want). You will need to give 'guest' access to the ADA community, otherwise ADA will not be able to retrieve the ADA community info from the ada2release stylesheet. Then use the 'Definitions' tab to add the necessary UI attributes, such as 'widget' and 'initial'. Now use this community to add UI attributes to concepts.

Error creating thumbnail: Unable to save thumbnail to destination

This provides a simple route to enter attributes without accessing the underlying XML files.

Definitions will take precedence in the following order:

  1. Attributes defined in the ADA definition file
  2. Attributes defined in myCommunity ada
  3. Attributes defined in the DECOR file

So it is possible to override what's defined in DECOR through an ada community, and to override that again in the ADA definition file. Note: ada communities will work on dataset level, whereas the ADA definition works on transaction level, thus allowing finer-grained control.

Making an ADA release

The next step is to execute some of the ADA stylesheets. Use ada2release.xsl to transform the ADA definitions to a release:

 demoapp-ada.xml -> [ada2release.xsl] -> demoapp-ada-release.xml

This process pulls in all the information from RetrieveTransaction and combines it with the UI logic from ADA.

<view id="1" type="crud" target="xforms"
  transactionId="2.16.840.1.113883.3.1937.99.62.3.4.2" 
  transactionEffectiveDate="2012-09-05T16:59:35">
    <name>Measurement Form</name>
    <implementation shortName="measurement_form"/>
    <dataset id="2.16.840.1.113883.3.1937.99.62.3.1.1" 
      effectiveDate="2012-05-30T11:32:36" statusCode="draft"
      transactionId="2.16.840.1.113883.3.1937.99.62.3.4.2" 
      transactionEffectiveDate="2012-09-05T16:59:35" 
      shortName="measurement_message">
      <concept minimumMultiplicity="0" maximumMultiplicity="*" 
        conformance="" isMandatory="false" 
        id="2.16.840.1.113883.3.1937.99.62.3.2.1"
        statusCode="draft" effectiveDate="2012-05-30T11:32:36" 
        type="group" widget="tab">
        <name language="en-US">Measurement</name>
        <desc language="en-US">Measurement of body weight on a specific date</desc>
        <implementation shortName="measurement" 
          xpath="/hl7:registrationProcess/hl7:organizer"/>

It still looks a lot like an ADA definition, with:

  • a <dataset> element where <concepts> was
  • implementation elements with
    • a @shortName, which is used for (amongst others) XML element names
    • an @xpath expression which shows where this concept resides in a HL7 document (only if all templates and templateAssociations are present).
  • all other information from dataset/concept and transaction/concept
  • plus the information which was added in the ADA definition, such as @widget

Generating an ADA App

The next step is convert demoapp-ada-release.xml to the necessary schemas, forms and other resources

 demoapp-ada-release.xml -> [release2newxml.xsl] -> empty XML
 demoapp-ada-release.xml -> [release2schema.xsl] -> XML Schema
 demoapp-ada-release.xml -> [release2xform.xsl]  -> XForms

The ADA XML format

The first transform generates an empty ADA XML instance:

 ada/projects/demoapp/new/measurement_message.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--New XML generator, 2014-05-13T13:17:04.038+02:00-->
<measurement_message id="new" app="demoapp"
  transactionRef="2.16.840.1.113883.3.1937.99.62.3.4.2" 
  transactionEffectiveDate="2012-09-05T16:59:35"
  versionDate="2014-05-13T13:16:14" 
  prefix="demoapp-" language="en-US">
   <measurement conceptId="2.16.840.1.113883.3.1937.99.62.3.2.1">
      <weight conceptId="2.16.840.1.113883.3.1937.99.62.3.2.3" value="" unit="kg"/>
      <weight_gain conceptId="2.16.840.1.113883.3.1937.99.62.3.2.13" value="false"/>
      <weight_gain_data conceptId="2.16.840.1.113883.3.1937.99.62.3.2.18">
         <amount_of_weight_gain conceptId="2.16.840.1.113883.3.1937.99.62.3.2.19" value="" unit="gram"/>
         <cause_of_weight_gain conceptId="2.16.840.1.113883.3.1937.99.62.3.2.20" value=""/>
      </weight_gain_data>
      <datetime conceptId="2.16.840.1.113883.3.1937.99.62.3.2.2" value=""/>
      <measured_by conceptId="2.16.840.1.113883.3.1937.99.62.3.2.5" value="1"/>
      <remarks conceptId="2.16.840.1.113883.3.1937.99.62.3.2.17" value=""/>
   </measurement>
   <person conceptId="2.16.840.1.113883.3.1937.99.62.3.2.6">
      <name conceptId="2.16.840.1.113883.3.1937.99.62.3.2.4" value=""/>
      <bsn conceptId="2.16.840.1.113883.3.1937.99.62.3.2.7" value=""/>
      <date_of_birth conceptId="2.16.840.1.113883.3.1937.99.62.3.2.8" value=""/>
      <length conceptId="2.16.840.1.113883.3.1937.99.62.3.2.15" value="" unit="m"/>
   </person>
</measurement_message>

The ADA XML is a very straightforward XML format. It's design principles are readability, conciseness and following the dataset as closely as possible. It has:

  • an XML element name taken from @shortName (since shortName discards spaces and most special characters, and is all lowercase, DECOR concept names must yield unique shortNames for ADA to work)
  • the tree structure of the dataset, making it easy to navigate
  • an optional conceptId (it may be absent since it can be calculated from the ADA release info, if needed)
  • @value attribute containing the entered value or the indexed localId for a code. @value might be left out for coded concepts as the value would then be in code, and could be unknown in which case @nullFlavor should be present
  • @unit for quantity units, @value holds the value
  • @root for identifier systems, @value holds the identifier
  • @nullFlavor for unknown @value. Supports any valid NullFlavor, e.g. UNK, MSK, NI. @nullFlavor should not co-exist with coded data. In this case @code will hold the @nullFlavor and @codeSystem points to the NullFlavor code system.
  • @code, @codeSystem, @codeSystemName, @codeSystemVersion, @preferred, @originalText attribute for coded concepts. @originalText is expected when NullFlavor is OTH.
  • @id supporting a value of type xml:id / xs:ID useful for referring to this concept
  • @datatype supporting any DECOR DataSetValueType. This is relevant when the dataset concept has the indeterminate value 'complex'. In addition to the DECOR datatypes, there is 'reference' which allows a @value to refer to a concept/@id in the same instance.

Valid combinations of attributes in ADA XML elements (@conceptId and @id are always valid):

  • @value
  • @value + @unit
  • @value + @root
  • @code + @codeSystem, optionally @value and/or @displayName, @preferred and/or @originalText
  • @nullFlavor, optionally with @unit or @root, never with @code
  • @datatype (only for complex concepts) with any of the above combinations

Retrieval of lists with more than one resource are bundled in FHIR style. Bundle is not in the FHIR namespace since it is not 100% compliant. This may change in the future.

<Bundle>
  <type value="searchset"/>
  <entry>
    <resource>
      <measurement_message ...>
      ...
      </measurement_message>
    </resource>
  </entry>
  <entry>
    <resource>
      <measurement_message ...>
      ...
      </measurement_message>
    </resource>
  </entry>
</Bundle>

The ADA JSON format

ADA also supports JSON, both as output and input format.

{"measurement_message": {
    "app": "demoapp",
    "transactionRef": "2.16.840.1.113883.3.1937.99.62.3.4.2",
    "transactionEffectiveDate": "2012-09-05T16:59:35",
    "versionDate": "",
    "prefix": "demoapp-",
    "language": "en-US",
    "title": "POC case 2",
    "id": "fc912512-7d4c-4cd6-a9c4-4912a23ecb77",
    "measurement": [{
        "conceptId": "2.16.840.1.113883.3.1937.99.62.3.2.1",
        "weight": [{
            "conceptId": "2.16.840.1.113883.3.1937.99.62.3.2.3",
            "value": 70,
            "unit": "kg",
            "datatype": "quantity"
        }],
        "weight_gain": [],
        "weight_gain_data": [],
        "length": [],
        "datetime": [],
        "measured_by": [{
            "conceptId": "2.16.840.1.113883.3.1937.99.62.3.2.5",
            "value": "1",
            "code": "P",
            "codeSystem": "2.16.840.1.113883.3.1937.99.62.3.5.1",
            "displayName": "Patiënt",
            "datatype": "code"
        }],
        "comments": []
    }],
    "person": [{
        "conceptId": "2.16.840.1.113883.3.1937.99.62.3.2.6",
        "name": [{
            "conceptId": "2.16.840.1.113883.3.1937.99.62.3.2.4",
            "value": "Marc",
            "datatype": "complex"
        }],
        "bsn": [{
            "conceptId": "2.16.840.1.113883.3.1937.99.62.3.2.7",
            "value": "12341234",
            "datatype": "identifier"
        }],
        "date_of_birth": [],
        "number_of_children": []
    }]
}}

The serialization rules are simple (and quite like the JSON format of FHIR):

  • The transaction element in serialized as a {name, value} pair.
  • All elements become JSON arrays. Of course 0..1 and 1..1 concepts items needn't be arrays, but a single approach allows applications to treat all concepts alike. Also, if a new version of the ADA app changes a concept to 1..*, old JSON data files will still interoperate.
  • All attributes become {name, value} pairs. Booleans, counts, decimal and quantity become literals (i.e. 6, true, false), others become strings (i.e. "Marc").
  • The datatype is serialized as well.

The ADA RESTful interface

ADA has a RESTful interface, also inspired by FHIR. The RESTful interface operates on /db/apps/ada, not /db/apps/ada-data. See the controller.xql in /db/apps/ada for details. The following methods are supported:

  • GET [base]/[app]/[id] reads a resource(where id is the uuid of the ADA XML)
  • GET [base]/[app]/new reads a new (empty) resource
  • GET [base]/[app] returns a list of all resources for this app (in a <Bundle>)
  • POST [base]/[app]/ will save the POSTed data. POST data should be an ADA XML file. If the uuid exists, it will be updated (if the user has access rights), if not, it will be created. (TODO: provide PUT interface.)
  • DELETE [base]/[app]/[id] will remove the resource.

An example is: http://localhost:8877/ada/projects/demoapp/3deb5f5f-3898-4c7c-94b9-cfe53c8e6d73 where:

Also the following parameters are allowed:

Parameter Values Description
format json, xml, html This overrides the Accept header. Permitted values are json, xml, html, and the corresponding media types (i.e. application/json etc.)
from an @id This retrieves the data with @id from the data collection, or if not available there, from the new collection and uses the 'from' data as prototype instead of the standard 'new' XML. This can be useful if for instance optional groups should be absent by default, or to prefill fields with default values. Create a default record using the UI, and use that record in the 'from' clause.
summary true, false If true, returns only summary data, which are the concepts which are defined in views of type 'index'.

ADA XML Schema

There are now two schemas:

 ada/projects/demoapp/schemas/measurement_message_draft.xsd
 ada/projects/demoapp/schemas/measurement_message.xsd

Both schemas validate the ADA XML format for measurement_message. The 'draft' version allows incomplete data to be stored in the database, i.e. when someone is filling out a complex form and wants to store it for later completion. A draft schema will allow @value and @unit to be absent on all nodes, even when mandatory in the transaction. The other schema checks all constraints from the dataset and scenario. A couple of 'ada-...' schemas are generated too. These are wrappers which validate the ADA XML as stored in the ADA data store (See The ADA XML Data Store).

ADA Views and Modules

Our two views are stored in:

 ada/projects/demoapp/views/measurement_index.xhtml
 ada/projects/demoapp/views/measurement_form.xhtml

We'll see those in action soon.

Deploying an ADA App

Install ADA into your eXist database. This will provide the following collections:

Collection Contains
apps/ada/core The stylesheets for ADA conversion. Not needed in eXist, but provided to make a complete package. The stylesheets are better run using an XML suite such as Oxygen XML.
apps/ada/helpers Here you'll find XQueries meant to be run in eXist manually (with eXide or from Oxygen). Mostly stuff to help you deploy your ADA apps.
apps/ada/modules Here are the XQueries central to ADA, for saving, getting and manipulating data. There are plenty of goodies for handling ADA data.
apps/ada-data/projects Each ADA App has its own collection below.
apps/ada/resources For now, ADA.css.

From helpers, open:

 create-project.xquery

Change $prefix to 'demoapp' and run. This will create the collection layout for your app. Then open:

 get-project-from-disk.xquery

Change $project to 'demoapp', $adaDir to the directory where the generated ADA app is, and run. This will import your app into the collection layout.

Collection Contains
apps/ada-data/projects/demoapp/data Where the ADA XML for this project will live.
apps/ada-data/projects/demoapp/definitions A copy of the ADA definition and ADA release. Just stored here for archival.
apps/ada-data/projects/demoapp/modules This now contains index.xquery for demoapp.
apps/ada-data/projects/demoapp/new The empty ADA XML template. Used in the XForms - don't edit this!
apps/ada-data/projects/demoapp/schemas Both the ADA XML Schema's.
apps/ada-data/projects/demoapp/views This now contains measurement_form.xhtml for demoapp.
apps/ada-data/projects/demoapp/xslt For later use, for stylesheets which transform ADA XML.

You may need to run:

 set-permissions.xquery

from helpers to give users access. This sets rather generous permissions: read access for all, and everyone in eXist group 'ada-user' can add records. Only the creator of a record can alter it.

Before running ADA, open conf.xml in apps/ada-data and change the values according to your local setup. The defaults will do only if eXist runs on localhost:8877 and Orbeon on localhost:8080.

If conf.xml contains an element <log/> all requests and POST data will be logged to ada-data/log.

Running the ADA App

Now point your browser to http://localhost:8877/ada/modules/index.xquery (or where your eXist lives). You may need to log into eXist, and should see something like:

Error creating thumbnail: Unable to save thumbnail to destination

with at least the demoapp included. Click demoapp to view

 http://localhost:8877/ada/projects/demoapp/modules/index.xquery

in action:

Error creating thumbnail: Unable to save thumbnail to destination

Not spectacular yet. Click 'New' to see:

 http://localhost:8080/art-decor/ada/demoapp/views/measurement_form.xhtml?id=new

This link tells ADA to use the measurement_form for a new (empty) instance. Note the red exclamation marks for data which is not yet valid. If you see nothing, or too little, you're probably not logged into ART. ADA uses the ART login for the time being for XForms. At the right top is a 'Login' link.

Error creating thumbnail: Unable to save thumbnail to destination

Fill out the form. You can add a second (or third, etc.) measurement with the '+ Measurement' button.

Error creating thumbnail: Unable to save thumbnail to destination

Don't forget the nice-looking tab2. This is where the ADA widgets came into action to create tabs.

Error creating thumbnail: Unable to save thumbnail to destination

Finally, save the data and return to the demoapp index:

Error creating thumbnail: Unable to save thumbnail to destination

We now see the two columns we defined for the index ('Datetime' and 'Name'). By default, ADA provides the username of the creator and the last update time.

The ADA XML data store

The ADA XML is stored in eXist-db in:

 apps/ada-data/db/demoapp/491e3a76-bf50-4e21-ac5a-67d93d498aae.xml

or any other uuid your XQuery favors at the moment. In this file, you'll find:

<adaxml>
    <meta status="new" created-by="marc" last-update-by="marc" 
      creation-date="2014-05-12T16:47:48.789+02:00" 
      last-update-date="2014-05-12T16:47:48.789+02:00"/>
    <data>
        <measurement_message app="demoapp" 
        ...
          <weight conceptId="2.16.840.1.113883.3.1937.99.62.3.2.3" 
            value="86" unit="kg"/>
          ...
          <remarks conceptId="2.16.840.1.113883.3.1937.99.62.3.2.17"/>
          ...
        </measurement_message>
    </data>
</adaxml>

The actual ADA XML is wrapped in an adaxml element, with:

  • a <meta> element, with
    • @status ('new', but could be 'sent' or 'failed' etc.)
    • @created-by
    • @last-update-by
    • @creation-date
    • @last-update-date
  • a element, with the actual ADA XML message, note:
    • values and units are provided
    • concepts without values have no @value, ADA will add it upon retrieval for the XForm.

The ADA XML storage format allows for data conversion. I.e. next to adaxml/data a HL7 transformer could create an adaxml/hl7 element with the HL7 message, etc. But that's for later.

In the eXist database, you will see:

 - ada (this contains ADA backend functionality common to all ADA apps)
 - ada-data 
   - backup
     - {my project} (with the data backup from the last package install)
   - db 
     - {my project} (with the actual data)
   - log (for logging)
   - projects
     - {my project} (with ADA app-specific functionality)

ADA packages

ADA can generate what's needed to build a package with release2package.xsl. You will still need to build the package yourself, either with something like ANT, or with eXide's "Download app" utility. If ADA is installed with a package, ADA will create a backup of existing data in the backup collection.

Troubleshooting ADA

When ADA contains data, and a new app is generated and deployed, many things can go wrong. The older data may not validate against the newer schema. There are two troubeshooting tools in ada.

 ada/projects/demoapp/modules/index-admin.xquery?app={app}

It is recommended to run index-admin always after deploying a new version of an app. It will show the status of the ADA XML in database, and through the 'Validate' Link, offer an detailed analysis if there are problems. It is also possible to inspect various REST interfaces, as well as XML and JSON. The index-admin also contains a 'Coverage' item. This checks how often concepts from the transaction's definition are used in ADA XML data. This is mainly useful when ADA is used to supply test data and test completeness needs to be established.

The other tool is the logger. Insert </log> in conf.xml in ada-data, and all calls and POSTed data are logged in ada-data/log. The <log/> value can be set at runtime. Turning the logging on and off requires dba rights on eXist.

All these functions can be accessed through the Dashboard:

 ada/projects/demoapp/modules/dashboard.xquery