Page tree
Skip to end of metadata
Go to start of metadata
Given:
  • REST Structure:
{
"uuid": "a9b3acca-7cd3-4b2a-a8ea-2c37589b2ced",
"name": "males aged 20 - 30",
"description": "males aged 20 - 30"
}
  • REST resource location:
http://demo2.muzima.org/openmrs/ws/rest/v1/cohort/a9b3acca-7cd3-4b2a-a8ea-2c37589b2ced?v=custom:(uuid,name,description)
If the objective is to download the resource, convert it into object called Cohort and save it locally, here is the solution:
  • Create Cohort class implementing the root object of the Search API, the Searchable class. This class is basically a simple POJO class to hold the data of the REST resource.

import com.muzima.search.api.model.object.Searchable;
public class Cohort extends Searchable {
	private String uuid;
	private String name;
	private String description;
	public String getUuid() {
		return uuid;
	}
	public void setUuid(final String uuid) {
		this.uuid = uuid;
	}
	public String getName() {
		return name;
	}
	public void setName(final String name) {
		this.name = name;
	}
	public void getDescription() {
		return description;
	}
	public void setDescription(final String description) {
		this.description = description;
	}
}
  • Create CohortResolver class implementing the top level Resolver class. The cohort resolver will help the API to decide where to download the REST resource and what authentication needed to access it.
import com.muzima.search.api.model.resolver.Resolver;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;
public class SearchCohortResolver extends BaseOpenmrsResolver {
	private static final String REPRESENTATION = "?v=custom:(uuid,name,description)";
	/**
 	* Return the full REST resource based on the parameters passed to the method.
 	*
 	* @param resourceParams the parameters of the resource to resolved.
 	* @return full uri to the REST resource.
	*/

	@Override
	public String resolve(final Map<String, String> resourceParams) throws IOException {
		StringBuilder paramBuilder = new StringBuilder();
		for (String key : resourceParams.keySet()) {
    		paramBuilder.append("&").append(key).append("=").append(URLEncoder.encode(resourceParams.get(key), "UTF-8"));
		}
		return getConfiguration().getServer() + "/ws/rest/v1/cohort" + REPRESENTATION + paramBuilder.toString();
	}
}

 

  • Create CohortAlgorithm class implementing the top level Algorithm class. The Algorithm class define a two way conversion between the REST resource's representation into the correct object.
import com.muzima.api.model.Cohort;
import com.muzima.search.api.model.object.Searchable;
import com.muzima.util.JsonUtils;
import net.minidev.json.JSONObject;

import java.io.IOException;

public class CohortAlgorithm extends BaseOpenmrsAlgorithm {
	private static final String REPRESENTATION = "?v=custom:(uuid,name,voided,size)";


	/**
	* Implementation of this method will define how the object will be serialized from the String representation.
	*
	* @param serialized string representation
	* @return the concrete object
	*/


	@Override
	public Searchable deserialize(final String serialized, final boolean isFullSerialization) throws IOException {
		Cohort cohort = new Cohort();
		cohort.setUuid(JsonUtils.readAsString(serialized, "$['uuid']"));
    	cohort.setName(JsonUtils.readAsString(serialized, "$['name']"));
    	cohort.setVoided(JsonUtils.readAsBoolean(serialized, "$['voided']"));
    	cohort.setSize(JsonUtils.readAsInteger(serialized, "$['size']"));
    	return cohort;
	}
	/**
	* Implementation of this method will define how the object will be de-serialized into the String representation.
	*
	* @param object
	* @return the string representation
	*/

	@Override
	public String serialize(final Searchable object, final boolean isFullSerialization) throws IOException {
		Cohort cohort = (Cohort) object;
		JSONObject jsonObject = new JSONObject();
		JsonUtils.writeAsString(jsonObject, "uuid", cohort.getUuid());
		JsonUtils.writeAsString(jsonObject, "name", cohort.getName());
		JsonUtils.writeAsBoolean(jsonObject, "voided", cohort.isVoided());
		JsonUtils.writeAsInteger(jsonObject, "size", cohort.getSize());
		return jsonObject.toJSONString();
	}
}

 

  • Create configuration to tie everything together. The configuration have the following element:
    • resource.name: Obviously, the name of the resource. The value of this field will be used to uniquely identify the resource in the pool of all registered resources inside ServiceContext class.
    • node.root: The root element in the REST resource's payload JSONPath expression. JSONPath is XPath expression for JSON data. See more about JSONPath.
    • resource.object: The target class of the REST resource's payload conversion process.
    • algorithm.class: The class which will be used to perform two conversion from the REST resource's payload into the correct object (the correct object is represented in resource.object) and vice versa.
    • resolver.class: The class which will point to the location where the API can get the REST resource and the authentication needed to access it.
    • field.unique: An element in the REST resource's payload which can be used to uniquely identify the resource among collection of resources.
    • field.searchable: Any elements in the REST resource's payload which are searchable.
{
	"configurations": [
		{
			"resource.name": "Cohort Resource",
			"node.root": "$",
			"resource.object": "Cohort",
			"algorithm.class": "CohortAlgorithm",
			"resolver.class": "CohortResolver",
			"field.unique": "uuid",
			"field.searchable":
			{
				"uuid": "$['uuid']",
				"name": "$['name']",
				"description": "$['description']"
			}
		}
	]
}

 

  • Create module to specify the location where lucene index will be stored
import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
public class LuceneModule extends AbstractModule {
	public static final String LUCENE_DIRECTORY = File.separator + "lucene";
	/**
	* Configures a {@link com.google.inject.Binder} via the exposed methods.
	*/
	@Override
	protected void configure() {
		String tmpDirectory = System.getProperty("java.io.tmpdir");
		bind(String.class)
		.annotatedWith(Names.named("configuration.lucene.directory"))
		.toInstance(tmpDirectory + LUCENE_DIRECTORY);
		bind(String.class)
		.annotatedWith(Names.named("configuration.lucene.document.key"))
		.toInstance("uuid");
	}
}

 

  • Download and save the object locally
...
Injector injector = Guice.createInjector(new SearchModule(), new LuceneModule());
// we need to get the service context which will hold our resources for future use :)
ServiceContext context = injector.getInstance(ServiceContext.class);
// configuration.json here should point to the actual file of the above configuration file.
context.registerResources("configuration.json");
RestAssuredService service = injector.getInstance(RestAssuredService.class);
// get the configuration of the Resource configuration above using the name of the configuration
Resource resource = context.getResource("Cohort Resource");
// this will download the cohort as a list of searchable
List<Searchable> searchables = service.loadObjects("0ca78602-737f-408d-8ced-386ad12367db", resource);
// here, we can do whatever we want with the searchables (save it locally?)
service.createObjects(searchables, resource);
// query local storage?
List<Searchable> localSearchables = service.getObjects("0ca78602-737f-408d-8ced-386ad12367db", resource);
...
  • No labels