use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.
the class EventStreamAdherenceReportGenerator method generate.
public EventStreamAdherenceReport generate(AdherenceState state) {
LocalDate earliestDate = LATEST_LOCAL_DATE;
LocalDate latestDate = EARLIEST_LOCAL_DATE;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
String earliestEventId = null;
for (TimelineMetadata meta : state.getMetadata()) {
if (meta.isTimeWindowPersistent()) {
continue;
}
int startDay = meta.getSessionInstanceStartDay();
int endDay = meta.getSessionInstanceEndDay();
String eventId = meta.getSessionStartEventId();
Integer daysSinceEvent = state.getDaysSinceEventById(eventId);
DateTime timestamp = state.getEventTimestampById(eventId);
LocalDate localDate = (timestamp == null) ? null : timestamp.toLocalDate();
LocalDate startDate = (localDate == null) ? null : localDate.plusDays(startDay);
LocalDate endDate = (localDate == null) ? null : localDate.plusDays(endDay);
// Produce one report for each event ID. Create them lazily as we find each eventId;
EventStream stream = state.getEventStreamById(eventId);
stream.setDaysSinceEvent(daysSinceEvent);
stream.setStudyBurstId(meta.getStudyBurstId());
stream.setStudyBurstNum(meta.getStudyBurstNum());
// Get the adherence information for this session instance and derive the state of the session
AdherenceRecord record = state.getAdherenceRecordByGuid(meta.getSessionInstanceGuid());
SessionCompletionState sessionState = calculateSessionState(record, startDay, endDay, daysSinceEvent);
// Retrieve the event stream. All items in this stream start on the same day, but can end on different days
EventStreamDay eventStreamDay = state.getEventStreamDayByKey(meta);
eventStreamDay.setStartDay(startDay);
eventStreamDay.setStartDate(startDate);
// Create a window entry (windows are flattened in the list of timeline metadata records...all session
// records in the metadata table are actually session window records)
EventStreamWindow windowEntry = new EventStreamWindow();
windowEntry.setSessionInstanceGuid(meta.getSessionInstanceGuid());
windowEntry.setTimeWindowGuid(meta.getTimeWindowGuid());
windowEntry.setEndDay(endDay);
windowEntry.setEndDate(endDate);
windowEntry.setState(sessionState);
eventStreamDay.addTimeWindow(windowEntry);
if (startDate != null && startDate.isBefore(earliestDate)) {
earliestDate = startDate;
earliestEventId = eventStreamDay.getStartEventId();
}
if (endDate != null && endDate.isAfter(latestDate)) {
latestDate = endDate;
}
if (min > startDay) {
min = startDay;
}
if (max < endDay) {
max = endDay;
}
}
DayRange dayRange = null;
if (min <= max) {
dayRange = new DayRange(min, max);
}
DateRange dateRange = null;
if (earliestDate.isBefore(latestDate)) {
dateRange = new DateRange(earliestDate, latestDate);
}
EventStreamAdherenceReport report = new EventStreamAdherenceReport();
report.setTimestamp(state.getNow());
report.setClientTimeZone(state.getClientTimeZone());
report.setAdherencePercent(state.calculateAdherencePercentage());
report.setDayRangeOfAllStreams(dayRange);
report.setDateRangeOfAllStreams(dateRange);
report.setEarliestEventId(earliestEventId);
for (String eventId : state.getStreamEventIds()) {
report.getStreams().add(state.getEventStreamById(eventId));
}
report.setProgression(calculateProgress(state, report.getStreams()));
return report;
}
use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.
the class StudyAdherenceReportGenerator method generate.
public StudyAdherenceReport generate(AdherenceState state) {
EventStreamAdherenceReport eventReport = EventStreamAdherenceReportGenerator.INSTANCE.generate(state);
LocalDate studyStartDate = getStudyStartDate(state, eventReport);
EventStream studyStream = new EventStream();
Set<String> unsetEventIds = new HashSet<>();
Set<String> unscheduledSessions = new HashSet<>();
Map<String, DateTime> eventTimestamps = new HashMap<>();
LocalDate todayLocal = state.getNow().toLocalDate();
// Remap all the event streams to one event stream — the study event stream
for (EventStream stream : eventReport.getStreams()) {
for (List<EventStreamDay> days : stream.getByDayEntries().values()) {
for (EventStreamDay oneDay : days) {
if (oneDay.getStartDate() != null) {
// Map this stream into the study stream
Integer numDays = Days.daysBetween(studyStartDate, oneDay.getStartDate()).getDays();
studyStream.addEntry(numDays, oneDay);
String eventId = oneDay.getStartEventId();
eventTimestamps.put(eventId, state.getEventTimestampById(eventId));
} else {
// Note for the report the events and sessions that are not applicable to this user
unsetEventIds.add(oneDay.getStartEventId());
unscheduledSessions.add(oneDay.getSessionName());
}
}
}
}
// study-wide progress
ParticipantStudyProgress progression = calculateProgress(state, ImmutableList.of(studyStream));
// Break this study stream down into weeks. TreeMap sorts the weeks by week number
Map<Integer, StudyReportWeek> weekMap = new TreeMap<>();
for (Map.Entry<Integer, List<EventStreamDay>> entry : studyStream.getByDayEntries().entrySet()) {
int week = entry.getKey() / 7;
// Day of week can be negative if the week was negative... just flip it
int dayOfWeek = Math.abs(entry.getKey() % 7);
StudyReportWeek oneWeek = weekMap.get(week);
if (oneWeek == null) {
oneWeek = new StudyReportWeek();
oneWeek.setStartDate(studyStartDate.plusDays(week * 7));
oneWeek.setWeekInStudy(week + 1);
weekMap.put(week, oneWeek);
}
List<EventStreamDay> days = oneWeek.getByDayEntries().get(dayOfWeek);
days.addAll(entry.getValue());
}
;
Collection<StudyReportWeek> weeks = weekMap.values();
StudyReportWeek currentWeek = null;
for (StudyReportWeek oneWeek : weeks) {
calculateRowsAndLabels(oneWeek, todayLocal);
// If there’s a day in this week that is “today”, set a flag for all day entries on that day
LocalDate firstDayOfWeek = oneWeek.getStartDate();
LocalDate lastDayOfWeek = oneWeek.getStartDate().plusDays(7);
if (BridgeUtils.isLocalDateInRange(firstDayOfWeek, lastDayOfWeek, todayLocal)) {
currentWeek = oneWeek;
for (List<EventStreamDay> days : oneWeek.getByDayEntries().values()) {
for (EventStreamDay oneDay : days) {
if (oneDay.getStartDate().isEqual(todayLocal)) {
days.forEach(day -> day.setToday(true));
}
}
}
}
// current one) but not the weeks after todayLocal.
if (BridgeUtils.isLocalDateInRange(oneWeek.getStartDate(), null, todayLocal)) {
int weekAdh = AdherenceUtils.calculateAdherencePercentage(oneWeek.getByDayEntries());
oneWeek.setAdherencePercent(weekAdh);
}
}
Integer adherence = null;
if (progression != ParticipantStudyProgress.NO_SCHEDULE) {
adherence = calculateAdherencePercentage(ImmutableList.of(studyStream));
}
NextActivity nextActivity = null;
if (currentWeek == null) {
nextActivity = getNextActivity(weeks, todayLocal);
}
DateRange dateRange = null;
if (eventReport.getDateRangeOfAllStreams() != null) {
dateRange = new DateRange(studyStartDate, eventReport.getDateRangeOfAllStreams().getEndDate());
}
for (StudyReportWeek oneWeek : weeks) {
for (List<EventStreamDay> days : oneWeek.getByDayEntries().values()) {
for (EventStreamDay oneDay : days) {
oneDay.setStudyBurstId(null);
oneDay.setStudyBurstNum(null);
oneDay.setSessionName(null);
oneDay.setWeek(null);
oneDay.setStartDay(null);
for (EventStreamWindow window : oneDay.getTimeWindows()) {
window.setEndDay(null);
// This cannot be removed, or the window will be removed from persisted collection
// window.setTimeWindowGuid(null);
}
}
}
}
StudyAdherenceReport report = new StudyAdherenceReport();
report.setDateRange(dateRange);
report.setWeeks(weeks);
report.setCurrentWeek(currentWeek);
report.setNextActivity(nextActivity);
report.setProgression(progression);
report.setAdherencePercent(adherence);
report.setEventTimestamps(eventTimestamps);
report.setUnsetEventIds(unsetEventIds);
report.setUnscheduledSessions(unscheduledSessions);
return report;
}
use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.
the class ParticipantScheduleGenerator method generate.
public ParticipantSchedule generate(AdherenceState state, Timeline timeline) {
Multimap<LocalDate, ScheduledSession> chronology = LinkedHashMultimap.create();
LocalDate earliestDate = LATEST_LOCAL_DATE;
LocalDate latestDate = EARLIEST_LOCAL_DATE;
Map<String, DateTime> eventTimestamps = new HashMap<>();
for (ScheduledSession schSession : timeline.getSchedule()) {
String eventId = schSession.getStartEventId();
DateTime eventTimestamp = state.getEventTimestampById(eventId);
if (eventTimestamp == null) {
continue;
}
LocalDate startDate = eventTimestamp.plusDays(schSession.getStartDay()).toLocalDate();
LocalDate endDate = eventTimestamp.plusDays(schSession.getEndDay()).toLocalDate();
eventTimestamps.put(eventId, eventTimestamp);
ScheduledSession.Builder builder = schSession.toBuilder();
builder.withStartDate(startDate);
builder.withEndDate(endDate);
if (startDate.isBefore(earliestDate)) {
earliestDate = startDate;
}
if (endDate.isAfter(latestDate)) {
latestDate = endDate;
}
for (ScheduledAssessment schAssessment : schSession.getAssessments()) {
ScheduledAssessment.Builder asmtBuilder = new ScheduledAssessment.Builder().withRefKey(schAssessment.getRefKey()).withInstanceGuid(schAssessment.getInstanceGuid());
builder.withScheduledAssessment(asmtBuilder.build());
}
// null these out, not useful
schSession.getTimeWindow().setGuid(null);
builder.withStartDay(null);
builder.withEndDay(null);
chronology.put(startDate, builder.build());
}
// chronology.size() is the total number of pairs, not the total number of keys (and thus correct).
List<ScheduledSession> scheduledSessions = Lists.newArrayListWithCapacity(chronology.size());
for (LocalDate date : chronology.keySet()) {
scheduledSessions.addAll(chronology.get(date));
}
scheduledSessions.sort(SCHEDULED_SESSION_COMPARATOR);
DateRange range = null;
if (earliestDate.isBefore(latestDate)) {
range = new DateRange(earliestDate, latestDate);
}
ParticipantSchedule schedule = new ParticipantSchedule();
schedule.setCreatedOn(state.getNow());
schedule.setClientTimeZone(state.getClientTimeZone());
schedule.setDateRange(range);
schedule.setSchedule(scheduledSessions);
schedule.setSessions(timeline.getSessions().stream().map(SessionInfo::createScheduleEntry).collect(toList()));
schedule.setAssessments(timeline.getAssessments());
schedule.setStudyBursts(timeline.getStudyBursts());
schedule.setEventTimestamps(eventTimestamps);
return schedule;
}
use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.
the class UserDataDownloadViaSqsServiceTest method test.
@Test
public void test() throws Exception {
// main test strategy is to validate that the args get transformed and sent to SQS as expected
// mock config
BridgeConfig mockConfig = mock(BridgeConfig.class);
when(mockConfig.getProperty(CONFIG_KEY_UDD_SQS_QUEUE_URL)).thenReturn(SQS_URL);
// mock SQS
AmazonSQSClient mockSqsClient = mock(AmazonSQSClient.class);
SendMessageResult mockSqsResult = new SendMessageResult().withMessageId(SQS_MESSAGE_ID);
ArgumentCaptor<String> sqsMessageCaptor = ArgumentCaptor.forClass(String.class);
when(mockSqsClient.sendMessage(eq(SQS_URL), sqsMessageCaptor.capture())).thenReturn(mockSqsResult);
// set up test service
UserDataDownloadViaSqsService testService = new UserDataDownloadViaSqsService();
testService.setBridgeConfig(mockConfig);
testService.setSqsClient(mockSqsClient);
// test inputs
DateRange dateRange = new DateRange(LocalDate.parse(START_DATE), LocalDate.parse(END_DATE));
// execute
testService.requestUserData(TEST_APP_ID, USER_ID, dateRange);
// Validate SQS args.
String sqsMessageText = sqsMessageCaptor.getValue();
JsonNode sqsMessageNode = JSON_OBJECT_MAPPER.readTree(sqsMessageText);
// first assert parent node
assertEquals(sqsMessageNode.size(), 2);
assertEquals(sqsMessageNode.get(REQUEST_KEY_SERVICE).asText(), UDD_SERVICE_TITLE);
// then assert body node
JsonNode msgBody = sqsMessageNode.path(REQUEST_KEY_BODY);
assertEquals(msgBody.size(), 5);
assertEquals(msgBody.get(REQUEST_KEY_STUDY_ID).textValue(), TEST_APP_ID);
assertEquals(msgBody.get(REQUEST_KEY_APP_ID).textValue(), TEST_APP_ID);
assertEquals(msgBody.get(REQUEST_KEY_USER_ID).textValue(), USER_ID);
assertEquals(msgBody.get(REQUEST_KEY_START_DATE).textValue(), START_DATE);
assertEquals(msgBody.get(REQUEST_KEY_END_DATE).textValue(), END_DATE);
}
use of org.sagebionetworks.bridge.models.DateRange in project BridgeServer2 by Sage-Bionetworks.
the class ParticipantScheduleTest method canSerialize.
@Test
public void canSerialize() {
Schedule2 schedule = Schedule2Test.createValidSchedule();
Timeline timeline = Scheduler.INSTANCE.calculateTimeline(schedule);
ScheduledSession schSession = timeline.getSchedule().get(0);
schSession.getTimeWindow().setGuid(null);
schSession = schSession.toBuilder().withStartDay(null).withEndDay(null).withStartEventId(null).withStartDate(LocalDate.parse("2022-01-10")).withEndDate(LocalDate.parse("2022-01-13")).withState(SessionCompletionState.ABANDONED).build();
DateRange range = new DateRange(CREATED_ON.toLocalDate(), MODIFIED_ON.toLocalDate());
ParticipantSchedule participantSchedule = new ParticipantSchedule();
participantSchedule.setDateRange(range);
participantSchedule.setCreatedOn(CREATED_ON);
participantSchedule.setClientTimeZone(TEST_CLIENT_TIME_ZONE);
participantSchedule.setSchedule(ImmutableList.of(schSession));
participantSchedule.setAssessments(timeline.getAssessments());
participantSchedule.setSessions(timeline.getSessions());
participantSchedule.setStudyBursts(timeline.getStudyBursts());
participantSchedule.setEventTimestamps(ImmutableMap.of("enrollment", MODIFIED_ON));
JsonNode node = BridgeObjectMapper.get().valueToTree(participantSchedule);
assertEquals(node.size(), 9);
assertEquals(node.get("createdOn").textValue(), CREATED_ON.toString());
assertEquals(node.get("clientTimeZone").textValue(), TEST_CLIENT_TIME_ZONE);
assertEquals(node.get("dateRange").get("startDate").textValue(), CREATED_ON.toLocalDate().toString());
assertEquals(node.get("dateRange").get("endDate").textValue(), MODIFIED_ON.toLocalDate().toString());
assertEquals(node.get("type").textValue(), "ParticipantSchedule");
JsonNode schNode = node.get("schedule").get(0);
assertEquals(schNode.get("startDate").textValue(), "2022-01-10");
assertEquals(schNode.get("endDate").textValue(), "2022-01-13");
assertEquals(schNode.get("state").textValue(), "abandoned");
// This is completely tested in ScheduledSessionTest
JsonNode sessionNode = node.get("sessions").get(0);
assertEquals(sessionNode.get("guid").textValue(), "BBBBBBBBBBBBBBBBBBBBBBBB");
assertEquals(sessionNode.get("performanceOrder").textValue(), "randomized");
// This is completely tested in SessionInfoTest
JsonNode asmtNode = node.get("assessments").get(0);
assertEquals(asmtNode.get("guid").textValue(), ASSESSMENT_1_GUID);
// This is completely tested in AssessmentInfoTest
JsonNode sbNode = node.get("studyBursts").get(0);
assertEquals(sbNode.get("identifier").textValue(), "burst1");
assertEquals(sbNode.get("originEventId").textValue(), "timeline_retrieved");
assertEquals(sbNode.get("interval").textValue(), "P1W");
assertEquals(sbNode.get("occurrences").intValue(), 2);
assertEquals(sbNode.get("type").textValue(), "StudyBurstInfo");
JsonNode etNode = node.get("eventTimestamps");
assertEquals(etNode.get("enrollment").textValue(), MODIFIED_ON.toString());
}
Aggregations