org.openmhealth.shim.fitbit.mapper.FitbitPhysicalActivityDataPointMapper.java Source code

Java tutorial

Introduction

Here is the source code for org.openmhealth.shim.fitbit.mapper.FitbitPhysicalActivityDataPointMapper.java

Source

/*
 * 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 org.openmhealth.schema.domain.omh.*;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.Optional;

import static org.openmhealth.schema.domain.omh.DurationUnit.DAY;
import static org.openmhealth.schema.domain.omh.DurationUnit.MILLISECOND;
import static org.openmhealth.schema.domain.omh.KcalUnit.KILOCALORIE;
import static org.openmhealth.schema.domain.omh.LengthUnit.KILOMETER;
import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.*;

/**
 * A mapper that translates responses from the Fitbit Resource API <code>activities/date</code> endpoint into {@link
 * PhysicalActivity} data points.
 *
 * @author Chris Schaefbauer
 * @see <a href="https://dev.fitbit.com/docs/activity/#get-daily-activity-summary">API documentation</a>
 */
public class FitbitPhysicalActivityDataPointMapper extends FitbitDataPointMapper<PhysicalActivity> {

    @Override
    protected String getListNodeName() {
        return "activities";
    }

    @Override
    protected Optional<DataPoint<PhysicalActivity>> asDataPoint(JsonNode node) {

        String activityName = asRequiredString(node, "name");
        PhysicalActivity.Builder activityBuilder = new PhysicalActivity.Builder(activityName);

        Boolean hasStartTime = asRequiredBoolean(node, "hasStartTime");

        /*
         * hasStartTime is true if the startTime value has been set, which is required of entries through the user
         * GUI and from sensed data, however some of their data import workflows may set dummy values for these
         * (00:00:00), in which case hasStartTime is false and the time shouldn't be used
         */
        if (hasStartTime) {

            Optional<LocalDateTime> localStartDateTime = asOptionalLocalDateTime(node, "startDate", "startTime");
            Optional<Long> duration = asOptionalLong(node, "duration");

            if (localStartDateTime.isPresent()) {

                OffsetDateTime offsetStartDateTime = combineDateTimeAndTimezone(localStartDateTime.get());
                if (duration.isPresent()) {
                    activityBuilder.setEffectiveTimeFrame(TimeInterval.ofStartDateTimeAndDuration(
                            offsetStartDateTime, new DurationUnitValue(MILLISECOND, duration.get())));
                } else {
                    activityBuilder.setEffectiveTimeFrame(offsetStartDateTime);
                }
            }
        } else {
            Optional<LocalDate> localStartDate = asOptionalLocalDate(node, "startDate");

            if (localStartDate.isPresent()) {
                // in this case we have a date, but no time, so we set the startTime to beginning of day on the
                // startDate, add the offset, then set the duration as the entire day
                LocalDateTime localStartDateTime = localStartDate.get().atStartOfDay();
                OffsetDateTime offsetStartDateTime = combineDateTimeAndTimezone(localStartDateTime);
                activityBuilder.setEffectiveTimeFrame(TimeInterval.ofStartDateTimeAndDuration(offsetStartDateTime,
                        new DurationUnitValue(DAY, 1)));
            }
        }

        Optional<Double> distance = asOptionalDouble(node, "distance");

        if (distance.isPresent()) {
            // by default fitbit returns metric unit values (https://wiki.fitbit.com/display/API/API+Unit+System), so
            // this assumes that the response is using the default for distance (KM)
            activityBuilder.setDistance(new LengthUnitValue(KILOMETER, distance.get()));
        }

        asOptionalDouble(node, "calories")
                .ifPresent(calories -> activityBuilder.setCaloriesBurned(new KcalUnitValue(KILOCALORIE, calories)));

        PhysicalActivity measure = activityBuilder.build();
        Optional<Long> externalId = asOptionalLong(node, "logId");

        return Optional.of(newDataPoint(measure, externalId.orElse(null)));
    }
}