Metadata Sharing Project

This page refers to a ?Summer Of Code 2010 project.  Please see the ?Metadata Sharing Module documentation page for the outcome.

Deliverables, in approximate order

  1. Manually select metadata to export
  2. Export a package of metadata as a file
  3. Import a packaged file, thus creating/editing metadata locally
  4. Publish a packaged file, along with extra version info
  5. Subscribe to a published URL, thus importing a package
  6. Check for updates on subscribed URLs, and download them


Timeline includes only the three first deliverables that are initially planned to be implemented within the GSoC project.

Show timeline


Sourcecode is available in the OpenMRS repository:

Class Diagram

Select Metadata to export

  • Need a way to find and list all OpenmrsMetadata
    • Initially we can hardcode known classes with their getter methods.
    • For release, we need this to be dynamic, so that metadata provided by modules is included too.
      • Maybe scan the classpath for classes that implement the interface
    • Maybe introspect all OpenmrsServices, looking for getAll() and get*ByUuid(String) methods
    • Need a special-case to handle 'Concept' which does not implement OpenmrsMetadata, but is the most valuable type of metadata to share.
  • Identify dependencies between object
    • Fail on circular dependencies

Export a Metadata Package

  • XML? JSON?
    • if there's no specific reason for JSON I'd prefer we stick to XML -Rafal
      • sounds fair -Darius
  • Serialization
    • org.openmrs.User: drop any of these properties
    • primitives: easy
    • lists, sets, maps: easy
    • anything that extends OpenmrsMetadata: replace with class & uuid
    • anything else (i.e. complex objects that are not OpenmrsMetadata): recursively serialize
  • All serialized in one file? Or a zip of individual files for each metadata item? Order matters.
    • Why order matters anyway? -Rafal
      • Because of dependencies between metadata. If you are exporting a form, and that form contains a concept, you need to import the concept before the form. -Darius

Import a Metadata Package

  • Go through package one item at a time.
  • If there's already an existing local entity with the same uuid, ask the user if they want to overwrite. (If not, cancel the whole thing.)
  • Once all is confirmed, create/save all items
  • Keep imported packages around to help with reverting local modifications later

(This may belong under Subscribing, but it might be possible to implement it when importing.)

  • Identify local modifications
    • Version 1: fail on this case
    • Version 2: allow overwriting local changes
    • Version 3: allow merge, ignore, etc

Publish a Metadata Package

  • Publish a package with
    • Name
    • Version/revision (auto incrementing integer, nothing fancy like "4.0.2")
    • Publishing authority (e.g. "WHO")
    • What URL to check for updates
  • This will create a file (which should be persisted on the server) and can be downloaded, or fetched via a web service

Subscribe to a Metadata Package

  • Two ways:
    1. upload a file
    2. enter a URL
  • Some sort of download / check / apply / error workflow and status
  • Once a package is applied, record what version/revision of it we're at.

Check for updates

  • Check all update urls to see which subscribed packages have new versions available. (Checking versions should use very little bandwidth.)
  • Download the new version, apply it, and record new version/revision we're at.
  • Also allow this to be done by uploading a file (e.g. distributing updates via USB stick)

(Way) Future Work

  • A package should be able to be a link to other packages, e.g. a 'Rwanda Locations' package could actually just be symlinks to 'Rwanda District Hospitals' and 'Rwanda Health Centers'
  • Allow replacement, e.g. I am downloading a metadata package that contains a concept for Weight, but I want to use my own (compatible) weight concept, not the downloaded one.
    • One solution for this would be to use a uuid-->uuid mapping table. If a user chooses an existing concept, you map the uuids so that any future import can continue without a problem