@Test
  public void shouldSendEventWhenChannelWasUpdated() {
    Channel channel = new Channel("displayName", BUNDLE_SYMBOLIC_NAME, VERSION);

    EventParameter eventParameter = new EventParameter("displayName", "eventKey");
    TriggerEvent triggerEvent =
        new TriggerEvent("displayName", "subject", null, Arrays.asList(eventParameter), "");

    channel.getTriggerTaskEvents().add(triggerEvent);

    when(channelsDataService.findByModuleName(channel.getModuleName())).thenReturn(channel);

    when(bundleContext.getBundles()).thenReturn(new Bundle[] {bundle});
    when(bundle.getSymbolicName()).thenReturn(BUNDLE_SYMBOLIC_NAME);

    ArgumentCaptor<MotechEvent> captor = ArgumentCaptor.forClass(MotechEvent.class);
    Channel updatedChannel = new Channel("displayName2", BUNDLE_SYMBOLIC_NAME, VERSION);
    updatedChannel.getTriggerTaskEvents().add(triggerEvent);
    channelService.addOrUpdate(updatedChannel);

    ArgumentCaptor<TransactionCallback> transactionCaptor =
        ArgumentCaptor.forClass(TransactionCallback.class);
    verify(channelsDataService).doInTransaction(transactionCaptor.capture());
    transactionCaptor.getValue().doInTransaction(null);
    verify(channelsDataService).update(channel);

    verify(eventRelay).sendEventMessage(captor.capture());

    MotechEvent event = captor.getValue();

    assertEquals(CHANNEL_UPDATE_SUBJECT, event.getSubject());
    assertEquals(BUNDLE_SYMBOLIC_NAME, event.getParameters().get(CHANNEL_MODULE_NAME));
  }
  @Test
  public void shouldSendEventWhenChannelWasDeleted() {
    Channel channel = new Channel("displayName", BUNDLE_SYMBOLIC_NAME, VERSION);

    when(channelsDataService.findByModuleName(channel.getModuleName())).thenReturn(channel);
    when(bundleContext.getBundles()).thenReturn(new Bundle[] {bundle});
    when(bundle.getSymbolicName()).thenReturn(BUNDLE_SYMBOLIC_NAME);

    ArgumentCaptor<MotechEvent> captor = ArgumentCaptor.forClass(MotechEvent.class);
    Channel deletedChannel = new Channel("displayName2", BUNDLE_SYMBOLIC_NAME, VERSION);
    channelService.delete(deletedChannel.getModuleName());

    ArgumentCaptor<TransactionCallback> transactionCaptor =
        ArgumentCaptor.forClass(TransactionCallback.class);
    verify(channelsDataService).doInTransaction(transactionCaptor.capture());
    transactionCaptor.getValue().doInTransaction(null);
    verify(channelsDataService).delete(channel);

    verify(eventRelay).sendEventMessage(captor.capture());

    MotechEvent event = captor.getValue();

    assertEquals(CHANNEL_DEREGISTER_SUBJECT, event.getSubject());
    assertEquals(BUNDLE_SYMBOLIC_NAME, event.getParameters().get(CHANNEL_MODULE_NAME));
  }
  @Test
  public void testShouldRaiseExceptionEventWhenIndexIsMalformed()
      throws FileNotFoundException, CaseParserException {

    CaseTask task = new CaseTask();

    List<IndexSubElement> subElements = new ArrayList<IndexSubElement>();

    subElements.add(new IndexSubElement(null, null, null));

    IndexTask indexTask = new IndexTask(subElements);

    task.setIndexTask(indexTask);

    ArgumentCaptor<MotechEvent> motechEventCaptor = ArgumentCaptor.forClass(MotechEvent.class);

    String xml = caseConverter.convertToCaseXml(task);

    verify(eventRelay).sendEventMessage(motechEventCaptor.capture());

    MotechEvent motechEvent = motechEventCaptor.getValue();

    Assert.assertEquals(motechEvent.getSubject(), EventSubjects.MALFORMED_CASE_EXCEPTION);

    Assert.assertNull(xml);
  }
  @MotechListener(subjects = EventKeys.CAMPAIGN_COMPLETED)
  public void handle(MotechEvent event) throws SchedulerException {
    String campaignName = (String) event.getParameters().get(EventKeys.CAMPAIGN_NAME_KEY);
    String externalId = (String) event.getParameters().get(EventKeys.EXTERNAL_ID_KEY);

    markEnrollmentAsComplete(externalId, campaignName);
  }
  @Test
  public void testShouldRaiseExceptionEventWhenCaseNameIsMissing()
      throws FileNotFoundException, CaseParserException {

    CaseTask task = new CaseTask();

    CreateTask createTask = new CreateTask();

    createTask.setOwnerId("OWNER_ID");

    createTask.setCaseType("CASE_TYPE");

    task.setCreateTask(createTask);

    ArgumentCaptor<MotechEvent> motechEventCaptor = ArgumentCaptor.forClass(MotechEvent.class);

    String xml = caseConverter.convertToCaseXml(task);

    verify(eventRelay).sendEventMessage(motechEventCaptor.capture());

    MotechEvent motechEvent = motechEventCaptor.getValue();

    Assert.assertEquals(motechEvent.getSubject(), EventSubjects.MALFORMED_CASE_EXCEPTION);

    Assert.assertNull(xml);
  }
  private MotechEvent CommcareFormStubEvent(String formId, List<String> cases) {
    MotechEvent event = CommcareFormStubEvent(formId);

    event.getParameters().put(EventDataKeys.CASE_IDS, cases);

    return event;
  }
  @Override
  public void onFailure(LiveException e) {
    MotechEvent event = callRequest.getOnFailureEvent();

    if (event != null) {
      CallDetailRecord cdr = new CallDetailRecord(CallDisposition.FAILED, e.getMessage());

      Map<String, Object> parameters = event.getParameters();
      parameters.put(IVREventDelegate.CALL_DETAIL_RECORD_KEY, cdr);

      eventRelay.sendEventMessage(event);
    }
  }
  @Test
  public void shouldNotSendSmsIfMotherCaseIsNull() throws Exception {
    String motechCaseId = "motechCaseId";

    MotechEvent event = new MotechEvent();
    event.getParameters().put(EventKeys.MOTHER_CASE_ID, motechCaseId);

    when(commcareCaseService.getCaseByCaseId(motechCaseId)).thenReturn(null);

    listener.postPartumMissedVisitHandler(event);

    verify(fixtureIdMap, never()).getPhoneForFixture(anyString());
    verify(smsService, never()).send(any(OutgoingSms.class));
  }
 public void handle(MotechEvent event) {
   if (event.getSubject().equals(EventKeys.CREATED_NEW_PATIENT_SUBJECT)) {
     created = true;
   } else if (event.getSubject().equals(EventKeys.UPDATED_PATIENT_SUBJECT)) {
     updated = true;
   } else if (event.getSubject().equals(EventKeys.PATIENT_DECEASED_SUBJECT)) {
     deceased = true;
   } else if (event.getSubject().equals(EventKeys.DELETED_PATIENT_SUBJECT)) {
     deleted = true;
   }
   eventParameters = event.getParameters();
   synchronized (lock) {
     lock.notify();
   }
 }
  @Test
  public void shouldSendEmailForHandledEvent() {

    eventHandler.handleEvent(event);

    verify(emailSender).sendPasswordResetReminder(event.getParameters());
  }
  public static String getStringValue(MotechEvent event, String key) {
    String ret = null;
    try {
      ret = (String) event.getParameters().get(key);
    } catch (ClassCastException e) {
      log.warn("Event: " + event + " Key: " + key + " is not a String");
    }

    return ret;
  }
  public static Integer getIntegerValue(MotechEvent event, String key) {
    Integer ret = null;
    try {
      ret = (Integer) event.getParameters().get(key);
    } catch (ClassCastException e) {
      log.warn("Event: " + event + " Key: " + key + " is not an Integer");
    }

    return ret;
  }
示例#13
0
  private Object getValue(MotechEvent event, String key) {
    Map<String, Object> parameters = event.getParameters();
    Object value = null;

    if (MapUtils.isNotEmpty(parameters)) {
      value = parameters.get(key);
    }

    return value;
  }
  @Override
  public void onBusy(AsteriskChannel asteriskChannel) {
    MotechEvent event = callRequest.getOnBusyEvent();

    if (event != null) {
      org.asteriskjava.live.CallDetailRecord aCDR = asteriskChannel.getCallDetailRecord();
      CallDetailRecord cdr =
          new CallDetailRecord(
              aCDR.getStartDate(),
              aCDR.getEndDate(),
              aCDR.getAnswerDate(),
              translateDisposition(aCDR.getDisposition()),
              aCDR.getDuration());

      Map<String, Object> parameters = event.getParameters();
      parameters.put(IVREventDelegate.CALL_DETAIL_RECORD_KEY, cdr);

      eventRelay.sendEventMessage(event);
    }
  }
  @Test
  public void shouldNotSendSmsIfPhoneIsNotSet() throws Exception {
    String motechCaseId = "motechCaseId";
    String phuId = "phuId";

    Map<String, String> motherCaseFieldValues = new HashMap<>();
    motherCaseFieldValues.put(Commcare.PHU_ID, phuId);

    MotechEvent event = new MotechEvent();
    event.getParameters().put(EventKeys.MOTHER_CASE_ID, motechCaseId);

    when(commcareCaseService.getCaseByCaseId(motechCaseId)).thenReturn(motherCase);
    when(motherCase.getFieldValues()).thenReturn(motherCaseFieldValues);

    when(fixtureIdMap.getPhoneForFixture(phuId)).thenReturn(null);

    listener.postPartumMissedVisitHandler(event);

    verify(smsService, never()).send(any(OutgoingSms.class));
  }
  @Test
  public void shouldSendSmsWhenTwoAppointmentsAreMissed() throws Exception {
    String motechCaseId = "motechCaseId";
    String phuId = "phuId";
    String phone = "phone";
    String userId = "userId";
    String firstName = "firstName";
    String lastName = "lastName";

    Map<String, String> motherCaseFieldValues = new HashMap<>();
    motherCaseFieldValues.put(Commcare.PHU_ID, phuId);

    MotechEvent event = new MotechEvent();
    event.getParameters().put(EventKeys.MOTHER_CASE_ID, motechCaseId);

    when(commcareCaseService.getCaseByCaseId(motechCaseId)).thenReturn(motherCase);
    when(motherCase.getFieldValues()).thenReturn(motherCaseFieldValues);
    when(motherCase.getUserId()).thenReturn(userId);

    when(fixtureIdMap.getPhoneForFixture(phuId)).thenReturn(phone);

    when(commcareUserService.getCommcareUserById(userId)).thenReturn(commcareUser);
    when(commcareUser.getFirstName()).thenReturn(firstName);
    when(commcareUser.getLastName()).thenReturn(lastName);

    when(settings.getLanguage()).thenReturn(LANGUAGE);
    when(cmsLiteService.getStringContent(LANGUAGE, POST_PARTUM_VISITS_MESSAGE_NAME))
        .thenReturn(new StringContent(LANGUAGE, POST_PARTUM_VISITS_MESSAGE_NAME, "%s"));

    listener.postPartumMissedVisitHandler(event);

    ArgumentCaptor<OutgoingSms> captor = ArgumentCaptor.forClass(OutgoingSms.class);

    verify(smsService).send(captor.capture());

    OutgoingSms value = captor.getValue();

    assertEquals(asList(phone), value.getRecipients());
    assertEquals(firstName + " " + lastName, value.getMessage());
  }
示例#17
0
  /**
   * Closes or marks the alert as read based on the received event.
   *
   * @param event the event - id of the alert to update is the only expected parameter
   */
  @MotechListener(subjects = {CLOSE_ALERT_SUBJECT, MARK_ALERT_READ_SUBJECT})
  public void updateStatus(MotechEvent event) {
    Long id = Long.valueOf(getValueAsString(event, ALERT_ID));
    UpdateCriteria criteria = new UpdateCriteria();

    if (event.getSubject().equals(CLOSE_ALERT_SUBJECT)) {
      criteria.status(AlertStatus.CLOSED);
    } else {
      criteria.status(AlertStatus.READ);
    }

    alertService.update(id, criteria);
  }
示例#18
0
  /**
   * Parses the event and creates a {@link
   * org.motechproject.dhis2.rest.domain.TrackedEntityInstanceDto} and a {@link
   * org.motechproject.dhis2.rest.domain.EnrollmentDto} which is then sent to the DHIS2 server via
   * {@link org.motechproject.dhis2.rest.service.DhisWebService}
   *
   * @param event pertaining to combined DHIS2 tracked entity instance creation and enrollment.
   */
  @MotechListener(subjects = {EventSubjects.CREATE_AND_ENROLL})
  public void handleCreateAndEnroll(MotechEvent event) {
    Map<String, Object> params = prepareDhisAttributesMap(event.getParameters());
    Map<String, Object> enrollmentParams = new HashMap<>();

    enrollmentParams.put(EventParams.PROGRAM, params.remove(EventParams.PROGRAM));
    enrollmentParams.put(EventParams.DATE, params.remove(EventParams.DATE));

    enrollmentParams.put(EventParams.EXTERNAL_ID, params.get(EventParams.EXTERNAL_ID));
    enrollmentParams.put(EventParams.LOCATION, params.get(EventParams.LOCATION));

    handleCreate(new MotechEvent(EventSubjects.CREATE_ENTITY, params));
    handleEnrollment(new MotechEvent(EventSubjects.ENROLL_IN_PROGRAM, enrollmentParams));
  }
示例#19
0
  /**
   * Parses the MotechEvent and creates a {@link
   * org.motechproject.dhis2.rest.domain.TrackedEntityInstanceDto} which is then sent to the DHIS2
   * server via {@link org.motechproject.dhis2.rest.service.DhisWebService}
   *
   * @param event MotechEvent pertaining to tracked entity instance creation.
   */
  @MotechListener(subjects = EventSubjects.CREATE_ENTITY)
  public void handleCreate(MotechEvent event) {
    LOGGER.debug("Handling CREATE_ENTITY MotechEvent");
    Map<String, Object> params = prepareDhisAttributesMap(event.getParameters());
    String externalUUID = (String) params.remove(EventParams.EXTERNAL_ID);
    TrackedEntityInstanceDto trackedEntityInstance = createTrackedEntityInstanceFromParams(params);

    LOGGER.debug("Sending request to create entity to the DHIS Web Service");
    DhisStatusResponse response = dhisWebService.createTrackedEntityInstance(trackedEntityInstance);

    LOGGER.trace("Received response from the DHIS server. Status: {}", response.getStatus());
    if (response.getStatus() == DhisStatus.SUCCESS || response.getStatus() == DhisStatus.OK) {
      trackedEntityInstanceMappingService.create(externalUUID, response.getReference());
    }
  }
  @Test
  public void shouldExecutePutRequest() {
    httpAgent.execute(url, data, Method.PUT, headers, credentials);

    ArgumentCaptor<MotechEvent> motechEventArgumentCaptor =
        ArgumentCaptor.forClass(MotechEvent.class);
    verify(asynchronousCall).send(motechEventArgumentCaptor.capture());
    MotechEvent eventMessageSent = motechEventArgumentCaptor.getValue();

    assertEquals(Method.PUT, eventMessageSent.getParameters().get(EventDataKeys.METHOD));
    assertEquals(data, (String) eventMessageSent.getParameters().get(EventDataKeys.DATA));
    assertEquals(url, eventMessageSent.getParameters().get(EventDataKeys.URL));
    assertEquals(headers, eventMessageSent.getParameters().get(EventDataKeys.HEADERS));
    assertEquals(
        credentials.getUsername(), eventMessageSent.getParameters().get(EventDataKeys.USERNAME));
    assertEquals(
        credentials.getPassword(), eventMessageSent.getParameters().get(EventDataKeys.PASSWORD));
  }
示例#21
0
  /**
   * Parses the event and creates a{@link org.motechproject.dhis2.rest.domain.DataValueSetDto}which
   * is then sent to the DHIS2 server via {@link
   * org.motechproject.dhis2.rest.service.DhisWebService}
   *
   * @param event
   */
  @MotechListener(subjects = EventSubjects.SEND_DATA_VALUE_SET)
  public void handleDataValueSet(MotechEvent event) {
    Map<String, Object> params = prepareDhisAttributesMap(event.getParameters());
    String dataSet = (String) params.get(EventParams.DATA_SET);
    String completeDate = (String) params.get(EventParams.COMPLETE_DATE);
    String period = (String) params.get(EventParams.PERIOD);
    String orgUnitId = (String) params.get(EventParams.LOCATION);
    String categoryOptionCombo = (String) params.get(EventParams.CATEGORY_OPTION_COMBO);
    String comment = (String) params.get(EventParams.COMMENT);
    String attributeOptionCombo = (String) params.get(EventParams.ATTRIBUTE_OPTION_COMBO);
    Map<String, Object> dataValues = (Map<String, Object>) params.get(EventParams.DATA_VALUES);

    List<DataValueDto> dataValueDtos = new ArrayList<>();

    for (Object o : dataValues.entrySet()) {
      Entry pair = (Entry) o;
      String dataElement = (String) pair.getKey();
      String dataElementId = dataElementService.findByName(dataElement).getUuid();
      String value = (String) pair.getValue();
      DataValueDto dataValueDto = new DataValueDto();
      dataValueDto.setDataElement(dataElementId);
      dataValueDto.setValue(value);

      dataValueDtos.add(dataValueDto);
    }

    DataValueSetDto dataValueSetDto = new DataValueSetDto();
    dataValueSetDto.setDataSet(dataSet);
    dataValueSetDto.setPeriod(period);
    dataValueSetDto.setCompleteDate(completeDate);
    dataValueSetDto.setOrgUnit(orgUnitId);
    dataValueSetDto.setDataValues(dataValueDtos);
    dataValueSetDto.setAttributeOptionCombo(attributeOptionCombo);
    dataValueSetDto.setCategoryOptionCombo(categoryOptionCombo);
    dataValueSetDto.setComment(comment);
    dhisWebService.sendDataValueSet(dataValueSetDto);
  }
示例#22
0
  /**
   * Parses the event and creates a {@link org.motechproject.dhis2.rest.domain.DataValueDto} which
   * is then sent to the DHIS2 server via {@link
   * org.motechproject.dhis2.rest.service.DhisWebService}
   *
   * @param event
   */
  @MotechListener(subjects = EventSubjects.SEND_DATA_VALUE)
  public void handleDataValue(MotechEvent event) {

    Map<String, Object> params = event.getParameters();

    DataElement dataElement =
        dataElementService.findByName((String) params.get(EventParams.DATA_ELEMENT));

    if (dataElement == null) {
      throw new DataElementNotFoundException(
          "The data element "
              + params.get(EventParams.DATA_ELEMENT)
              + " that was sent did not match any values imported from DHIS2. Please make sure that the "
              + "data element field matches a data element name in the DHIS2 module");
    }

    String orgUnitId = (String) params.get(EventParams.LOCATION);
    String period = (String) params.get(EventParams.PERIOD);
    String value = (String) params.get(EventParams.VALUE);
    String categoryOptionCombo = (String) params.get(EventParams.CATEGORY_OPTION_COMBO);
    String comment = (String) params.get(EventParams.COMMENT);

    DataValueDto dataValueDto = new DataValueDto();
    dataValueDto.setDataElement(dataElement.getUuid());
    dataValueDto.setValue(value);
    dataValueDto.setOrgUnit(orgUnitId);
    dataValueDto.setPeriod(period);
    dataValueDto.setCategoryOptionCombo(categoryOptionCombo);
    dataValueDto.setComment(comment);

    DataValueSetDto dataValueSetDto = new DataValueSetDto();
    List<DataValueDto> dataValueDtos = new ArrayList<>();
    dataValueDtos.add(dataValueDto);
    dataValueSetDto.setDataValues(dataValueDtos);

    dhisWebService.sendDataValueSet(dataValueSetDto);
  }
示例#23
0
 /**
  * Parses the MotechEvent and creates a {@link org.motechproject.dhis2.rest.domain.EnrollmentDto}
  * which is then sent to the DHIS2 server via {@link
  * org.motechproject.dhis2.rest.service.DhisWebService}
  *
  * @param event MotechEvent pertaining to enrolling a tracked entity instance in a program.
  */
 @MotechListener(subjects = {EventSubjects.ENROLL_IN_PROGRAM})
 public void handleEnrollment(MotechEvent event) {
   Map<String, Object> params = prepareDhisAttributesMap(event.getParameters());
   EnrollmentDto enrollment = createEnrollmentFromParams(params);
   dhisWebService.createEnrollment(enrollment);
 }
示例#24
0
 /**
  * Parses the MotechEvent and creates a {@link org.motechproject.dhis2.rest.domain.DhisEventDto}
  * which is then sent to the DHIS2 server via {@link
  * org.motechproject.dhis2.rest.service.DhisWebService}
  *
  * @param event MotechEvent pertaining to a DHIS2 program stage event.
  */
 @MotechListener(subjects = {EventSubjects.UPDATE_PROGRAM_STAGE})
 public void handleStageUpdate(MotechEvent event) {
   Map<String, Object> params = prepareDhisAttributesMap(event.getParameters());
   DhisEventDto dhisEventDto = createDhisEventFromParams(params);
   dhisWebService.createEvent(dhisEventDto);
 }
  @Override
  /** Sends an SMS */
  public void send(OutgoingSms sms) {

    // todo: cache that?
    Configs configs = new ConfigReader(settingsFacade).getConfigs();
    Config config;
    Template template;

    if (sms.hasConfig()) {
      config = configs.getConfig(sms.getConfig());
    } else {
      logger.debug("No config specified, using default config.");
      config = configs.getDefaultConfig();
    }
    template = templates.getTemplate(config.getTemplateName());

    // todo: die if things aren't right, right?
    // todo: SMS_SCHEDULE_FUTURE_SMS research if any sms provider provides that, for now assume not.

    Integer maxSize = template.getOutgoing().getMaxSmsSize();
    String header = config.getSplitHeader();
    String footer = config.getSplitFooter();
    Boolean excludeLastFooter = config.getExcludeLastFooter();
    // todo: maximum number of supported recipients : per template/provider and/or per http specs

    // todo - cr - move that to the Config object so calculated only once ?
    // todo - cr - investigate if that might be a problem on windows
    // -2 to account for the added \n after the header and before the footer
    if ((maxSize - header.length() - footer.length() - 2) <= 0) {
      throw new IllegalArgumentException(
          "The combined sizes of the header and footer templates are larger than the maximum SMS size!");
    }

    List<String> messageParts =
        splitMessage(sms.getMessage(), maxSize, header, footer, excludeLastFooter);
    List<List<String>> recipientsList =
        splitRecipientList(sms.getRecipients(), template.getOutgoing().getMaxRecipient());

    // todo: delivery_time on the sms provider's side if they support it?
    for (List<String> recipients : recipientsList) {
      if (sms.hasDeliveryTime()) {
        DateTime dt = sms.getDeliveryTime();
        for (String part : messageParts) {
          String motechId = generateMotechId();
          MotechEvent event =
              outboundEvent(
                  SmsEventSubjects.SCHEDULED,
                  config.getName(),
                  recipients,
                  part,
                  motechId,
                  null,
                  null,
                  null,
                  null);
          // MOTECH scheduler needs unique job ids, so adding motechId as job_id_key will do that
          event.getParameters().put(MotechSchedulerService.JOB_ID_KEY, motechId);
          event.getParameters().put(SmsEventParams.DELIVERY_TIME, dt);
          schedulerService.safeScheduleRunOnceJob(new RunOnceSchedulableJob(event, dt.toDate()));
          logger.info(
              String.format(
                  "Scheduling message [%s] to [%s] at %s.",
                  part.replace("\n", "\\n"), recipients, sms.getDeliveryTime()));
          // add one millisecond to the next sms part so they will be delivered in order
          // without that it seems Quartz doesn't fire events in the order they were scheduled
          dt = dt.plus(1);
          for (String recipient : recipients) {
            smsAuditService.log(
                new SmsRecord(
                    config.getName(),
                    OUTBOUND,
                    recipient,
                    part,
                    now(),
                    DeliveryStatus.SCHEDULED,
                    null,
                    motechId,
                    null,
                    null));
          }
        }
      } else {
        for (String part : messageParts) {
          String motechId = generateMotechId();
          eventRelay.sendEventMessage(
              outboundEvent(
                  SmsEventSubjects.PENDING,
                  config.getName(),
                  recipients,
                  part,
                  motechId,
                  null,
                  null,
                  null,
                  null));
          logger.info("Sending message [{}] to [{}].", part.replace("\n", "\\n"), recipients);
          for (String recipient : recipients) {
            smsAuditService.log(
                new SmsRecord(
                    config.getName(),
                    OUTBOUND,
                    recipient,
                    part,
                    now(),
                    DeliveryStatus.PENDING,
                    null,
                    motechId,
                    null,
                    null));
          }
        }
      }
    }
  }
 private MotechEvent CommcareFormStubEvent(String formId) {
   MotechEvent event = new MotechEvent(EventSubjects.FORM_STUB_EVENT);
   event.getParameters().put(EventDataKeys.FORM_ID, formId);
   return event;
 }