org.opendatakit.aggregate.externalservice.OhmageJsonServer.java Source code

Java tutorial

Introduction

Here is the source code for org.opendatakit.aggregate.externalservice.OhmageJsonServer.java

Source

/*
 * Copyright (C) 2009 Google Inc.
 * Copyright (C) 2010 University of Washington.
 *
 * 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.opendatakit.aggregate.externalservice;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.StringBody;
import org.opendatakit.aggregate.constants.common.ExternalServicePublicationOption;
import org.opendatakit.aggregate.constants.common.ExternalServiceType;
import org.opendatakit.aggregate.constants.common.OperationalStatus;
import org.opendatakit.aggregate.exception.ODKExternalServiceCredentialsException;
import org.opendatakit.aggregate.exception.ODKExternalServiceException;
import org.opendatakit.aggregate.form.IForm;
import org.opendatakit.aggregate.format.element.BasicElementFormatter;
import org.opendatakit.aggregate.format.element.OhmageJsonElementFormatter;
import org.opendatakit.aggregate.format.header.BasicHeaderFormatter;
import org.opendatakit.aggregate.submission.Submission;
import org.opendatakit.common.persistence.CommonFieldsBase;
import org.opendatakit.common.persistence.exception.ODKDatastoreException;
import org.opendatakit.common.persistence.exception.ODKEntityPersistException;
import org.opendatakit.common.persistence.exception.ODKOverQuotaException;
import org.opendatakit.common.security.common.EmailParser;
import org.opendatakit.common.utils.WebUtils;
import org.opendatakit.common.web.CallingContext;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
 *
 * @author wbrunette@gmail.com
 * @author mitchellsundt@gmail.com
 *
 */
public class OhmageJsonServer extends AbstractExternalService implements ExternalService {

    private static final Gson gson;
    static {
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(OhmageJsonTypes.Survey.class, new OhmageJsonTypes.Survey());
        builder.registerTypeAdapter(OhmageJsonTypes.RepeatableSet.class, new OhmageJsonTypes.RepeatableSet());
        builder.serializeNulls();
        builder.setPrettyPrinting();
        gson = builder.create();
    }

    /**
     * Datastore entity specific to this type of external service
     */
    private final OhmageJsonServer2ParameterTable objectEntity;

    private OhmageJsonServer(OhmageJsonServer2ParameterTable entity, FormServiceCursor formServiceCursor,
            IForm form, CallingContext cc) {
        super(form, formServiceCursor, new BasicElementFormatter(true, true, true, false),
                new BasicHeaderFormatter(true, true, true), cc);
        objectEntity = entity;
    }

    private OhmageJsonServer(OhmageJsonServer2ParameterTable entity, IForm form,
            ExternalServicePublicationOption externalServiceOption, String ownerEmail, CallingContext cc)
            throws ODKDatastoreException {
        this(entity, createFormServiceCursor(form, entity, externalServiceOption,
                ExternalServiceType.OHMAGE_JSON_SERVER, cc), form, cc);
        objectEntity.setOwnerEmail(ownerEmail);
    }

    public OhmageJsonServer(FormServiceCursor formServiceCursor, IForm form, CallingContext cc)
            throws ODKDatastoreException {
        this(retrieveEntity(OhmageJsonServer2ParameterTable.assertRelation(cc), formServiceCursor, cc),
                formServiceCursor, form, cc);
    }

    public OhmageJsonServer(IForm form, String campaignUrn, String campaignTimestamp, String user,
            String hashedPassword, String serverURL, ExternalServicePublicationOption externalServiceOption,
            String ownerEmail, CallingContext cc) throws ODKDatastoreException {
        this(newEntity(OhmageJsonServer2ParameterTable.assertRelation(cc), cc), form, externalServiceOption,
                ownerEmail, cc);

        // set stuff to ready for now
        // TODO: check for valid URL
        objectEntity.setOhmageCampaignCreationTimestamp(campaignTimestamp);
        objectEntity.setOhmageCampaignUrn(campaignUrn);
        objectEntity.setOhmageUsername(user);
        objectEntity.setOhmageHashedPassword(hashedPassword);
        objectEntity.setServerUrl(serverURL);
        persist(cc);
    }

    @Override
    public void initiate(CallingContext cc) throws ODKExternalServiceException, ODKEntityPersistException,
            ODKOverQuotaException, ODKDatastoreException {
        fsc.setIsExternalServicePrepared(true);
        fsc.setOperationalStatus(OperationalStatus.ACTIVE);

        persist(cc);
    }

    @Override
    protected String getOwnership() {
        return objectEntity.getOwnerEmail().substring(EmailParser.K_MAILTO.length());
    }

    public String getServerUrl() {
        return objectEntity.getServerUrl();
    }

    public String getOhmageUsername() {
        return objectEntity.getOhmageUsername();
    }

    public String getOhmageCampaignUrn() {
        return objectEntity.getOhmageCampaignUrn();
    }

    public String getOhmageCampaignCreationTimestamp() {
        return objectEntity.getOhmageCampaignCreationTimestamp();
    }

    public String getOhmageHashedPassword() {
        return objectEntity.getOhmageHashedPassword();
    }

    /**
     * Uploads a set of submissions to the ohmage system.
     *
     * @throws IOException
     * @throws ClientProtocolException
     * @throws ODKExternalServiceException
     * @throws URISyntaxException
     */
    public void uploadSurveys(List<OhmageJsonTypes.Survey> surveys, Map<UUID, ByteArrayBody> photos,
            CallingContext cc)
            throws ClientProtocolException, IOException, ODKExternalServiceException, URISyntaxException {

        MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.STRICT, null, UTF_CHARSET);
        // emit the configured publisher parameters if the values are non-empty...
        String value;
        value = getOhmageCampaignUrn();
        if (value != null && value.length() != 0) {
            StringBody campaignUrn = new StringBody(getOhmageCampaignUrn(), UTF_CHARSET);
            reqEntity.addPart("campaign_urn", campaignUrn);
        }
        value = getOhmageCampaignCreationTimestamp();
        if (value != null && value.length() != 0) {
            StringBody campaignCreationTimestamp = new StringBody(getOhmageCampaignCreationTimestamp(),
                    UTF_CHARSET);
            reqEntity.addPart("campaign_creation_timestamp", campaignCreationTimestamp);
        }
        value = getOhmageUsername();
        if (value != null && value.length() != 0) {
            StringBody user = new StringBody(getOhmageUsername(), UTF_CHARSET);
            reqEntity.addPart("user", user);
        }
        value = getOhmageHashedPassword();
        if (value != null && value.length() != 0) {
            StringBody hashedPassword = new StringBody(getOhmageHashedPassword(), UTF_CHARSET);
            reqEntity.addPart("passowrd", hashedPassword);
        }
        // emit the client identity and the json representation of the survey...
        StringBody clientParam = new StringBody(cc.getServerURL());
        reqEntity.addPart("client", clientParam);
        StringBody surveyData = new StringBody(gson.toJson(surveys));
        reqEntity.addPart("survey", surveyData);

        // emit the file streams for all the media attachments
        for (Entry<UUID, ByteArrayBody> entry : photos.entrySet()) {
            reqEntity.addPart(entry.getKey().toString(), entry.getValue());
        }

        HttpResponse response = super.sendHttpRequest(POST, getServerUrl(), reqEntity, null, cc);
        String responseString = WebUtils.readResponse(response);
        int statusCode = response.getStatusLine().getStatusCode();

        if (statusCode == HttpServletResponse.SC_UNAUTHORIZED) {
            throw new ODKExternalServiceCredentialsException(
                    "failure from server: " + statusCode + " response: " + responseString);
        } else if (statusCode >= 300) {
            throw new ODKExternalServiceException(
                    "failure from server: " + statusCode + " response: " + responseString);
        }
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof OhmageJsonServer)) {
            return false;
        }
        OhmageJsonServer other = (OhmageJsonServer) obj;
        return (objectEntity == null ? (other.objectEntity == null)
                : (other.objectEntity != null && objectEntity.equals(other.objectEntity)))
                && (fsc == null ? (other.fsc == null) : (other.fsc != null && fsc.equals(other.fsc)));
    }

    @Override
    protected void insertData(Submission submission, CallingContext cc) throws ODKExternalServiceException {
        try {
            OhmageJsonTypes.Survey survey = new OhmageJsonTypes.Survey();
            // TODO: figure out these values
            survey.setDate(null);
            survey.setLocation(null);
            survey.setLocation_status(null);
            survey.setSurvey_id(null);
            survey.setSurvey_lauch_context(null);
            survey.setTime(System.currentTimeMillis());
            survey.setTimezone(null);

            OhmageJsonElementFormatter formatter = new OhmageJsonElementFormatter();
            // called purely for side effects
            submission.getFormattedValuesAsRow(null, formatter, false, cc);
            survey.setResponses(formatter.getResponses());

            uploadSurveys(Collections.singletonList(survey), formatter.getPhotos(), cc);

        } catch (ODKExternalServiceCredentialsException e) {
            fsc.setOperationalStatus(OperationalStatus.BAD_CREDENTIALS);
            try {
                persist(cc);
            } catch (Exception ex) {
                ex.printStackTrace();
                throw new ODKExternalServiceException("unable to persist bad credentials state", ex);
            }
            throw e;
        } catch (ODKExternalServiceException e) {
            throw e;// don't wrap these
        } catch (Exception e) {
            throw new ODKExternalServiceException(e);
        }
    }

    @Override
    public String getDescriptiveTargetString() {
        return getServerUrl() + " campaign: " + getOhmageCampaignUrn();
    }

    protected CommonFieldsBase retrieveObjectEntity() {
        return objectEntity;
    }

    @Override
    protected List<? extends CommonFieldsBase> retrieveRepeatElementEntities() {
        return null;
    }

}