Java tutorial
/* * 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.fitbit.mapper; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.Lists; import org.openmhealth.schema.domain.omh.*; import org.openmhealth.shim.common.mapper.JsonNodeDataPointMapper; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.List; import java.util.Optional; import java.util.UUID; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.openmhealth.schema.domain.omh.DataPointHeader.Builder; import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.asOptionalLocalDateTime; import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.asRequiredNode; /** * The base class for mappers that translate Fitbit API responses to data points. * <p> * Fitbit does not include time zone information in its responses. These mappers therefore set the time zone of * effective time frame of the measures to UTC. There is currently no way to determine the correct time zone for a data * point returned by the the Fitbit API. * * @author Chris Schaefbauer * @author Emerson Farrugia */ public abstract class FitbitDataPointMapper<T extends SchemaSupport> implements JsonNodeDataPointMapper<T> { public static final String RESOURCE_API_SOURCE_NAME = "Fitbit Resource API"; @Override public List<DataPoint<T>> asDataPoints(List<JsonNode> responseNodes) { checkNotNull(responseNodes); checkArgument(responseNodes.size() == 1, "A single response node is allowed per call."); JsonNode listNode = asRequiredNode(responseNodes.get(0), getListNodeName()); List<DataPoint<T>> dataPoints = Lists.newArrayList(); 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(); /** * Creates a data point. * * @param measure the measure to set as the body of the data point * @param externalId the identifier of the measure as recorded by the data provider * @param <T> the measure type * @return a data point */ protected <T extends Measure> DataPoint<T> newDataPoint(T measure, @Nullable Long externalId) { DataPointAcquisitionProvenance acquisitionProvenance = new DataPointAcquisitionProvenance.Builder( RESOURCE_API_SOURCE_NAME).build(); if (externalId != null) { acquisitionProvenance.setAdditionalProperty("external_id", externalId); } DataPointHeader header = new Builder(UUID.randomUUID().toString(), measure.getSchemaId()) .setAcquisitionProvenance(acquisitionProvenance).build(); return new DataPoint<>(header, measure); } /** * TODO rewrite this, the names don't make sense * @param node a JSON node containing <code>date</code> and <code>time</code> properties * @return the equivalent OffsetDateTime */ protected Optional<OffsetDateTime> combineDateTimeAndTimezone(JsonNode node) { Optional<LocalDateTime> dateTime = asOptionalLocalDateTime(node, "date", "time"); Optional<OffsetDateTime> offsetDateTime = null; if (dateTime.isPresent()) { // FIXME fix the time zone offset to use the correct offset for the data point once it is fixed by Fitbit offsetDateTime = Optional.of(OffsetDateTime.of(dateTime.get(), ZoneOffset.UTC)); } return offsetDateTime; } /** * Transforms a {@link LocalDateTime} object into an {@link OffsetDateTime} object with a UTC time zone * * @param dateTime local date and time for the Fitbit response JSON node * @return the date and time based on the input dateTime parameter */ protected OffsetDateTime combineDateTimeAndTimezone(LocalDateTime dateTime) { // FIXME fix the time zone offset to use the appropriate offset for the data point once it is fixed by Fitbit return OffsetDateTime.of(dateTime, ZoneOffset.UTC); } /** * Maps a JSON response node from the Fitbit API into a data point. * * @return the data point */ protected abstract Optional<DataPoint<T>> asDataPoint(JsonNode node); }