...
Sometimes a module might want to remove an object. Assuming that the object may or may not exist, this can easily be done from inside a bundle with a combination of possible(...)
and uninstall(...)
, e.g.
...
Object installation ensures that individual metadata objects exist as expected in the database. Sometimes we are also concerned with the set of all objects of that type and this is where synchronization comes in:
Object synchronization guarantees that the set of all objects of a specific type in the database matches those in an object source
So synchronization differs from simply "installing all objects from a source" in this fundamental way: any existing object in the database that is not found in the source is uninstalled.
Defining the synchronization logic
The logic for a synchronization is provided via a custom implementation of ObjectSynchronization
. For example if we have a list of locations in a CSV file (same format as previous example), we could define a simple synchronization operation as follows:
Code Block | ||||
---|---|---|---|---|
| ||||
@Component public class LocationSynchronization implements ObjectSynchronization<Location> { @Autowired private LocationService locationService; @Override public List<Location> fetchAllExisting() { return locationService.getAllLocations(true); } @Override public Object getObjectSyncKey(Location obj) { return obj.getUuid(); } @Override public boolean updateRequired(Location incoming, Location existing) { return true; // Always update the existing object (not very efficient) } } |
In this example we instruct metadata deploy to always update existing objects in the database. A more efficient approach here is to compare the two objects and only update if they are actually different.
This synchronization can then be performed during a bundle installation by passing it and a suitable object source to the sync(...)
method, e.g.
Code Block | ||||
---|---|---|---|---|
| ||||
@Component public class LocationsMetadata extends AbstractMetadataBundle { @Autowired private LocationSynchronization locationSync; @Override public void install() throws Exception { sync(new LocationCsvSource("locations.csv"), locationSync); } } |
To maximize performance, internally metadata deploy will maintain a cache of all existing objects.
Info |
---|
You can synchronize on something other than the main identifier of an object by returning something else from |
Extending
Supporting new types
The module currently has support for most metadata objects in OpenMRS core but may be missing some. If you find it is missing support for an class defined in OpenMRS core then submit a ticket. If you need it to support a class defined outside of core then you can provide support for that type yourself as described below.
Providing new constructors
The class CoreConstructors
contains convenience constructors for many different classes. It is straightforward to define your own class of constructors which can be statically imported into a bundle class. You can use this to define constructors for new types, or additional constructors for core types, e.g.
Code Block | ||||
---|---|---|---|---|
| ||||
public class MyConstructors { public static MyMetadataType myMetadataType(String name, String description, String uuid) { MyMetadataType obj = new MyMetadataType(); obj.setName(name); obj.setDescription(description); obj.setUuid(uuid); return obj; } } |
Which can then be used in a bundle like this:
Code Block | ||||
---|---|---|---|---|
| ||||
import static com.example.MyConstructors.*; public class MyMetadata extends AbstractMetadataBundle { public static final class _MyMetadataType { public static final String EXAMPLE = "88B7D480-5147-4B44-AC66-9F5A20822F7"; } public void install() { install(myMetadataType("Name", "Testing", _MyMetadataType.EXAMPLE)); } } |
Providing new handlers
If you want to include a new object class in a bundle then you will also have to tell the module how to handle that class. You can do this by providing a new "deploy handler" component. For example the deploy handler for locations looks like this:
Code Block | ||||
---|---|---|---|---|
| ||||
@Handler(supports = { Location.class }) public class LocationDeployHandler extends AbstractObjectDeployHandler<Location> { @Autowired @Qualifier("locationService") private LocationService locationService; @Override public Location fetch(String uuid) { return locationService.getLocationByUuid(uuid); } @Override public Location save(Location obj) { return locationService.saveLocation(obj); } @Override public void uninstall(Location obj, String reason) { locationService.retireLocation(obj, reason); } } |
Links
- Module repository: https://addons.openmrs.org/#/show/org.openmrs.module.metadatadeploy
- Source code: https://github.com/openmrs/openmrs-module-metadatadeploy
- Issue tracker: https://tickets.openmrs.org/browse/DPLY
...
1.0
Initial public release.