How to add a new register to the server

OpenSRP Server Side Guide - developed by mPower, a step by step guide to building a register into the OpenSRP server.


This tutorial is involved in adding a new register to the opensrp server. The goal of the tutorial will be to build a register into the OpenSRP server side. This very basic module will allow us to cover a number of interesting topics, including:

  • Constants
  • Forms   
  • Entity   
  • Repository   
  • Data Transfer Object (DTO)
  • Service           
    • service       
    • form submission handler   
  • Scheduling


Constants
Constants represent different values throughout the course of opensrp. These values are used for directing to specific values to be used in any segment in the code.    

public class AllConstants {
public static final String OPENSRP_FORM_DATABASE_CONNECTOR = "opensrpFormDatabaseConnector";
public static final String OPENSRP_DATABASE_CONNECTOR = "opensrpDatabaseConnector";
public static final String OPENSRP_MCTS_DATABASE_CONNECTOR = "opensrpMCTSDatabaseConnector";
public static final String SPACE = " ";
public static final String BOOLEAN_TRUE_VALUE = "true";
public static final String BOOLEAN_FALSE_VALUE = "false";
public static final String AUTO_CLOSE_PNC_CLOSE_REASON = "Auto Close PNC";
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String EMPTY_STRING = "";
public static final String OPENSRP_ERRORTRACE_DATABASE="opensrpErrorTraceDatabaseConnector";
}


Forms
Forms are added in assets directory that hold specific fields. These fields may hold any range of user defined values. The values are retrieved in a particular register. This maps the fields within the form to OpenSRP database.
This is the form_definition for child .

"form_data_definition_version": "1",
"form": {
"bind_type": "eligible_couple",
"default_bind_path": "/model/instance/Child_Registration_EC_EngKan/",
"fields": [
{
"name": "id",
"shouldLoadValue": true
},
{
"name": "motherId",
"shouldLoadValue": true,
"source": "eligible_couple.mother.id"
},
{
"name": "childId",
"source": "eligible_couple.mother.child.id"
},


Entity
Entity is same as a model in which data is fetched from the database via repository classes. Entity has variables that holds for specific fields got from forms. These fields are initialized via service calls.


Repository
Repository is the part of opensrp used for handling database operations. This is responsible for the database creation and all these repositories have functions/methods where data is retrieved and returned as respective Entity objects. For example, the Child Register repository is here:

@Repository
public class AllChildren extends MotechBaseRepository<Child> {
@Autowired
protectedAllChildren(@Qualifier(AllConstants.OPENSRP_DATABASE_CONNECTOR) CouchDbConnector db) {
      super(Child.class, db);
}
  @GenerateView
  public Child findByCaseId(String caseId) {
  List<Child> children = queryView("by_caseId", caseId);
if(children == null || children.isEmpty()) {
          return null;
}
     return children.get(0);
  }
@View(name = "children_by_mother_id", map = "function(doc) {
if(doc.type === 'Child') { emit(doc.motherCaseId); } }")
       public List<Child> findByMotherId(String entityId) {
    return db.queryView(createQuery("children_by_mother_id").key(entityId).includeDocs(true),Child.class);
  }

 

Data Transfer Object (DTO)

DTO is a pattern. DTO is used to bring as much data as possible. So, if multiple requests are needed to bring information for a task, it can be brought and combined in a DTO so that only one request can bring all the necessary data. If it' used, a change in the requirements doesn't have any effect on the entity. The only alternative for DTOs is touse the domain from the presentation layer.

 

Service

Service is used to call methods when a form is submitted. Services are also used to sync and update the database record and also update timeline events.

The implementation of child service is shown here in ChildService .

@Service

public class ChildService {

   public static final String IMMUNIZATIONS_SEPARATOR = " ";

   private static Logger logger = LoggerFactory.getLogger(ChildService.class.toString());

   private ChildSchedulesService childSchedulesService;

   private AllMothers allMothers;

   private AllChildren allChildren;

   private ChildReportingService childReportingService;

   private ReportFieldsDefinition reportFieldsDefinition;


   @Autowired

   public ChildService(ChildSchedulesService childSchedulesService,

                       AllMothers allMothers,

                       AllChildren allChildren,

                       ChildReportingService childReportingService, ReportFieldsDefinition reportFieldsDefinition) {

       this.childSchedulesService = childSchedulesService;

       this.allMothers = allMothers;

       this.allChildren = allChildren;

       this.childReportingService = childReportingService;

       this.reportFieldsDefinition = reportFieldsDefinition;

   }


Form submission handler
This determines which service to call when a particular form is submitted. The mapping of forms and handlers is done in FormSubmissionRouter . The form handler determines the services to start and methods to call whenever a form is submitted.


Scheduling 

Scheduler is the most attractive feature of OpenSRP. A schedule can do any activity like sending messages, synchronizations etc... A scheduler executes a specific task at specific time intervals. But a schedule is free from human interactions. The schedule tracking module enrolls a client in a particular defined schedule. It consists of one or multiple milestones that represent windows of time in which certain conditions must be fulfilled in order to move on to the next milestone. Any women enrolled in schedules are notified via alerts/messages when they fulfill a particular schedule.

A woman may be enrolled in an unlimited number of schedules. If a woman is enrolled in a schedule she is already enrolled in, the service overwrites the previous enrollment with the new one. Schedule enrolls and unenrolls clients, updates enrollments and provides a preview of alert timings for an enrollment.


public interface ScheduleTrackingService {
   String enroll(EnrollmentRequest enrollmentRequest);
   void fulfillCurrentMilestone(String externalId, String scheduleName,
       LocalDate fulfillmentDate, Time fulfillmentTime);
   void fulfillCurrentMilestone(String externalId, String scheduleName,
       LocalDate fulfillmentDate);
   void unenroll(String externalId, List<String> scheduleNames);
   EnrollmentRecord getEnrollment(String externalId, String scheduleName);
   void updateEnrollment(String externalId, String scheduleName,
       UpdateCriteria updateCriteria);
   List<EnrollmentRecord> search(EnrollmentsQuery query);
   List<EnrollmentRecord> searchWithWindowDates(EnrollmentsQuery query);
   MilestoneAlerts getAlertTimings(EnrollmentRequest enrollmentRequest);
   void add(String scheduleJson);
   Schedule getScheduleByName(String scheduleName);
   List<Schedule> getAllSchedules();
   void remove(String scheduleName);
}


❖This would launch the new register