/* * Copyright 2015 Open mHealth * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openmhealth.shim.misfit.mapper; import com.fasterxml.jackson.databind.JsonNode; import org.openmhealth.schema.domain.omh.*; import org.openmhealth.shim.common.mapper.JsonNodeDataPointMapper; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; import static com.google.common.base.Preconditions.checkNotNull; import static org.openmhealth.schema.domain.omh.DataPointModality.SENSED; import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.asRequiredNode; /** * @author Emerson Farrugia */ public abstract class MisfitDataPointMapper<T extends SchemaSupport> implements JsonNodeDataPointMapper<T> { public static final String RESOURCE_API_SOURCE_NAME = "Misfit Resource API"; @Override public List<DataPoint<T>> asDataPoints(List<JsonNode> responseNodes) { // all mapped Misfit responses only require a single endpoint response checkNotNull(responseNodes); checkNotNull(responseNodes.size() == 1, "A single response node is allowed per call."); // all mapped Misfit responses contain a single list JsonNode listNode = asRequiredNode(responseNodes.get(0), getListNodeName()); List<DataPoint<T>> dataPoints = new ArrayList<>(); for (JsonNode listEntryNode : listNode) { asDataPoint(listEntryNode).ifPresent(dataPoints::add); } return dataPoints; } /** * @return the name of the list node used by this mapper */ protected abstract String getListNodeName(); /** * @param listEntryNode the list entry node * @return the data point mapped to from that entry, unless skipped */ protected abstract Optional<DataPoint<T>> asDataPoint(JsonNode listEntryNode); /** * @param measure the body of the data point * @param sourceName the name of the source of the measure * @param externalId the identifier of the measure as recorded by the data provider * @param sensed true if the measure is sensed by a device, false if it's manually entered, null otherwise * @param <T> the measure type * @return a data point */ protected <T extends Measure> DataPoint<T> newDataPoint(T measure, String sourceName, String externalId, Boolean sensed) { DataPointAcquisitionProvenance.Builder provenanceBuilder = new DataPointAcquisitionProvenance.Builder(sourceName); if (sensed != null && sensed) { provenanceBuilder.setModality(SENSED); } DataPointAcquisitionProvenance acquisitionProvenance = provenanceBuilder.build(); // TODO discuss the name of the external identifier, to make it clear it's the ID used by the source if (externalId != null) { acquisitionProvenance.setAdditionalProperty("external_id", externalId); } DataPointHeader header = new DataPointHeader.Builder(UUID.randomUUID().toString(), measure.getSchemaId()) .setAcquisitionProvenance(acquisitionProvenance) .build(); return new DataPoint<>(header, measure); } }