com.gallatinsystems.survey.dao.SurveyUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.gallatinsystems.survey.dao.SurveyUtils.java

Source

/*
 *  Copyright (C) 2013-2015 Stichting Akvo (Akvo Foundation)
 *
 *  This file is part of Akvo FLOW.
 *
 *  Akvo FLOW is free software: you can redistribute it and modify it under the terms of
 *  the GNU Affero General Public License (AGPL) as published by the Free Software Foundation,
 *  either version 3 of the License or any later version.
 *
 *  Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Affero General Public License included below for more details.
 *
 *  The full license text can also be seen at <http://www.gnu.org/licenses/agpl.html>.
 */

package com.gallatinsystems.survey.dao;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.waterforpeople.mapping.app.gwt.client.survey.SurveyDto;
import org.waterforpeople.mapping.app.web.dto.DataProcessorRequest;

import com.gallatinsystems.common.Constants;
import com.gallatinsystems.common.util.HttpUtil;
import com.gallatinsystems.common.util.PropertyUtil;
import com.gallatinsystems.survey.domain.CascadeResource;
import com.gallatinsystems.survey.domain.CascadeResource.Status;
import com.gallatinsystems.survey.domain.Question;
import com.gallatinsystems.survey.domain.QuestionGroup;
import com.gallatinsystems.survey.domain.QuestionOption;
import com.gallatinsystems.survey.domain.Survey;
import com.gallatinsystems.survey.domain.SurveyGroup;
import com.gallatinsystems.survey.domain.Translation;
import com.gallatinsystems.survey.domain.Translation.ParentType;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;

public class SurveyUtils {

    private static final Logger log = Logger.getLogger(SurveyUtils.class.getName());

    public static Survey copySurvey(Survey source, SurveyDto dto) {

        final SurveyDAO sDao = new SurveyDAO();
        final Survey tmp = new Survey();

        BeanUtils.copyProperties(source, tmp, Constants.EXCLUDED_PROPERTIES);
        // set name and surveyGroupId to values we got from the dashboard
        tmp.setCode(dto.getCode());
        tmp.setName(dto.getName());
        tmp.setSurveyGroupId(dto.getSurveyGroupId());

        tmp.setStatus(Survey.Status.COPYING);
        tmp.setPath(getPath(tmp));
        tmp.setVersion(Double.valueOf("1.0"));

        log.log(Level.INFO, "Copying `Survey` " + source.getKey().getId());
        final Survey newSurvey = sDao.save(tmp);

        log.log(Level.INFO, "New `Survey` ID: " + newSurvey.getKey().getId());

        SurveyUtils.copyTranslation(source.getKey().getId(), newSurvey.getKey().getId(), newSurvey.getKey().getId(),
                null, ParentType.SURVEY_NAME, ParentType.SURVEY_DESC);

        log.log(Level.INFO, "Running rest of copy functionality as a task...");

        final Queue queue = QueueFactory.getDefaultQueue();

        final TaskOptions options = TaskOptions.Builder.withUrl("/app_worker/dataprocessor")
                .param(DataProcessorRequest.ACTION_PARAM, DataProcessorRequest.COPY_SURVEY)
                .param(DataProcessorRequest.SURVEY_ID_PARAM, String.valueOf(newSurvey.getKey().getId()))
                .param(DataProcessorRequest.SOURCE_PARAM, String.valueOf(source.getKey().getId()));

        queue.add(options);

        return newSurvey;
    }

    public static QuestionGroup copyQuestionGroup(QuestionGroup source, Long newSurveyId, Map<Long, Long> qMap) {

        final QuestionGroupDao qgDao = new QuestionGroupDao();
        final QuestionGroup tmp = new QuestionGroup();

        BeanUtils.copyProperties(source, tmp, Constants.EXCLUDED_PROPERTIES);
        tmp.setSurveyId(null); // reset parent SurveyId, it will get set by the
                               // save action

        log.log(Level.INFO, "Copying `QuestionGroup` " + source.getKey().getId());

        final QuestionGroup newQuestionGroup = qgDao.save(tmp, newSurveyId);

        log.log(Level.INFO, "New `QuestionGroup` ID: " + newQuestionGroup.getKey().getId());

        final Queue queue = QueueFactory.getDefaultQueue();

        final TaskOptions options = TaskOptions.Builder.withUrl("/app_worker/dataprocessor")
                .param(DataProcessorRequest.ACTION_PARAM, DataProcessorRequest.COPY_QUESTION_GROUP)
                .param(DataProcessorRequest.QUESTION_GROUP_ID_PARAM,
                        String.valueOf(newQuestionGroup.getKey().getId()))
                .param(DataProcessorRequest.SOURCE_PARAM, String.valueOf(source.getKey().getId()));

        queue.add(options);

        return newQuestionGroup;
    }

    public static Question copyQuestion(Question source, Long newQuestionGroupId, Integer order, Long newSurveyId) {

        final QuestionDao qDao = new QuestionDao();
        final QuestionOptionDao qoDao = new QuestionOptionDao();
        final Question tmp = new Question();

        final String[] questionExcludedProps = { "questionOptionMap", "questionHelpMediaMap", "scoringRules",
                "translationMap", "order", "questionId" };

        final String[] allExcludedProps = (String[]) ArrayUtils.addAll(questionExcludedProps,
                Constants.EXCLUDED_PROPERTIES);

        BeanUtils.copyProperties(source, tmp, allExcludedProps);
        tmp.setOrder(order);
        if (source.getQuestionId() != null) {
            tmp.setQuestionId(source.getQuestionId() + "_copy");
        }
        log.log(Level.INFO, "Copying `Question` " + source.getKey().getId());

        final Question newQuestion = qDao.save(tmp, newQuestionGroupId);

        log.log(Level.INFO, "New `Question` ID: " + newQuestion.getKey().getId());

        log.log(Level.INFO, "Copying question translations");

        SurveyUtils.copyTranslation(source.getKey().getId(), newQuestion.getKey().getId(), newSurveyId,
                newQuestionGroupId, ParentType.QUESTION_NAME, ParentType.QUESTION_DESC, ParentType.QUESTION_TEXT,
                ParentType.QUESTION_TIP);

        if (!Question.Type.OPTION.equals(newQuestion.getType())) {
            // Nothing more to do
            return newQuestion;
        }

        final TreeMap<Integer, QuestionOption> options = qoDao.listOptionByQuestion(source.getKey().getId());

        if (options == null) {
            return newQuestion;
        }

        log.log(Level.INFO, "Copying " + options.values().size() + " `QuestionOption`");

        // Copying Question Options
        for (QuestionOption qo : options.values()) {
            SurveyUtils.copyQuestionOption(qo, newQuestion.getKey().getId(), newSurveyId, newQuestionGroupId);
        }

        return newQuestion;
    }

    public static QuestionOption copyQuestionOption(QuestionOption source, Long newQuestionId, Long newSurveyId,
            Long newQuestionGroupId) {

        final QuestionOptionDao qDao = new QuestionOptionDao();
        final QuestionOption tmp = new QuestionOption();

        BeanUtils.copyProperties(source, tmp, Constants.EXCLUDED_PROPERTIES);
        tmp.setQuestionId(newQuestionId);

        log.log(Level.INFO, "Copying `QuestionOption` " + source.getKey().getId());

        final QuestionOption newQuestionOption = qDao.save(tmp);

        log.log(Level.INFO, "New `QuestionOption` ID: " + newQuestionOption.getKey().getId());

        log.log(Level.INFO, "Copying question option translations");

        SurveyUtils.copyTranslation(source.getKey().getId(), newQuestionOption.getKey().getId(), newSurveyId,
                newQuestionGroupId, ParentType.QUESTION_OPTION);

        return newQuestionOption;
    }

    public static Survey resetSurveyState(Long surveyId) {
        final SurveyDAO sDao = new SurveyDAO();
        final Survey s = sDao.getById(surveyId);
        s.setStatus(Survey.Status.NOT_PUBLISHED);
        return sDao.save(s);
    }

    public static Survey retrieveSurvey(Long surveyId) {
        final SurveyDAO sDao = new SurveyDAO();
        return sDao.getById(surveyId);
    }

    public static SurveyGroup retrieveSurveyGroup(Long surveyGroupId) {
        final SurveyGroupDAO surveyGroupDAO = new SurveyGroupDAO();
        return surveyGroupDAO.getByKey(surveyGroupId);
    }

    public static String getPath(Survey s) {
        if (s == null) {
            return null;
        }

        final SurveyGroupDAO dao = new SurveyGroupDAO();
        final SurveyGroup sg = dao.getByKey(s.getSurveyGroupId());

        if (sg == null) {
            return null;
        }

        return sg.getPath() + "/" + s.getName();
    }

    public static String fixPath(String oldPath, String newName) {
        if (oldPath == null || newName == null) {
            return oldPath;
        }
        int idx = oldPath.lastIndexOf("/");
        if (idx >= 0) {
            return oldPath.substring(0, idx) + "/" + newName;
        }
        return oldPath;
    }

    public static List<Translation> getTranslations(Long parentId, ParentType... types) {
        final List<Translation> trs = new ArrayList<Translation>();
        final TranslationDao trDao = new TranslationDao();
        for (ParentType pt : types) {
            trs.addAll(trDao.findTranslations(pt, parentId).values());
        }
        return trs;
    }

    public static void saveTranslationCopy(List<Translation> trs, Long newParentId, Long newSurveyId,
            Long newQuestionGroupId) {
        final TranslationDao trDao = new TranslationDao();
        for (Translation t : trs) {
            Translation copy = new Translation();
            BeanUtils.copyProperties(t, copy, Constants.EXCLUDED_PROPERTIES);
            copy.setParentId(newParentId);
            copy.setQuestionGroupId(newQuestionGroupId);
            copy.setSurveyId(newSurveyId);
            trDao.save(copy);
        }
    }

    public static void copyTranslation(Long sourceParentId, Long copyParentId, Long newSurveyId,
            Long newQuestionGroupId, ParentType... types) {
        SurveyUtils.saveTranslationCopy(SurveyUtils.getTranslations(sourceParentId, types), copyParentId,
                newSurveyId, newQuestionGroupId);
    }

    /**
     * Sends a POST request to publish a cascade resource to a server defined by the `flowServices`
     * property
     *
     * @param cascadeResourceId The id of the cascade resource to publish
     * @return "failed" or "publishing requested", depending on the success.
     */
    public static String publishCascade(Long cascadeResourceId) {
        String status = "failed";
        CascadeResourceDao crDao = new CascadeResourceDao();
        CascadeResource cr = crDao.getByKey(cascadeResourceId);
        if (cr != null) {
            final String flowServiceURL = PropertyUtil.getProperty("flowServices");
            final String uploadUrl = PropertyUtil.getProperty("surveyuploadurl");

            if (flowServiceURL == null || "".equals(flowServiceURL)) {
                log.log(Level.SEVERE, "Error trying to publish cascade. Check `flowServices` property");
                return status;
            }

            try {
                final JSONObject payload = new JSONObject();
                payload.put("cascadeResourceId", cascadeResourceId.toString());
                payload.put("uploadUrl", uploadUrl);
                cr.setVersion(cr.getVersion() + 1);
                payload.put("version", cr.getVersion().toString());

                log.log(Level.INFO, "Sending cascade publish request for cascade: " + cascadeResourceId);

                final String postString = payload.toString();
                log.log(Level.INFO, "POSTing to: " + flowServiceURL);

                final String response = new String(
                        HttpUtil.doPost(flowServiceURL + "/publish_cascade", postString, "application/json"),
                        "UTF-8");

                log.log(Level.INFO, "Response from server: " + response);
                status = "publish requested";
                cr.setStatus(Status.PUBLISHING);
                crDao.save(cr);
            } catch (Exception e) {
                log.log(Level.SEVERE, "Error publishing cascade: " + e.getMessage(), e);
            }
        }
        return status;
    }

    /**
     * Sends a POST request of a collection of surveyIds to a server defined by the `flowServices`
     * property The property `alias` define the baseURL property that is sent in the request
     *
     * @param surveyIds Collection of ids (Long) that requires processing
     * @param action A string indicating the action that will be used, this string is used for
     *            building the URL, with the `flowServices` property + / + action
     * @return The response from the server or null when `flowServices` is not defined, or an error
     *         in the request happens
     */
    public static String notifyReportService(Collection<Long> surveyIds, String action) {
        final String flowServiceURL = PropertyUtil.getProperty("flowServices");
        final String baseURL = PropertyUtil.getProperty("alias");

        if (flowServiceURL == null || "".equals(flowServiceURL)) {
            log.log(Level.SEVERE,
                    "Error trying to notify server. It's not configured, check `flowServices` property");
            return null;
        }

        try {

            final JSONObject payload = new JSONObject();
            payload.put("surveyIds", surveyIds);
            payload.put("baseURL", (baseURL.startsWith("http") ? baseURL : "http://" + baseURL));

            log.log(Level.INFO, "Sending notification (" + action + ") for surveys: " + surveyIds);

            final String postString = "criteria=" + URLEncoder.encode(payload.toString(), "UTF-8");

            log.log(Level.FINE, "POST string: " + postString);

            final String response = new String(HttpUtil.doPost(flowServiceURL + "/" + action, postString), "UTF-8");

            log.log(Level.INFO, "Response from server: " + response);

            return response;
        } catch (Exception e) {
            log.log(Level.SEVERE, "Error notifying the report service: " + e.getMessage(), e);
        }
        return null;
    }

    /**
     * Given the path of an object, return a list of the paths of all its parent objects
     *
     * @param objectPath the path of an object
     * @param includeRootPath include the root path in the list of parent paths
     * @return
     */
    public static List<String> listParentPaths(String objectPath, boolean includeRootPath) {
        List<String> parentPaths = new ArrayList<String>();
        StringBuilder path = new StringBuilder(objectPath);
        while (path.length() > 1) {
            path.delete(path.lastIndexOf("/"), path.length());
            if (StringUtils.isNotBlank(path.toString())) {
                parentPaths.add(path.toString().trim());
            }
        }

        if (includeRootPath) {
            parentPaths.add("/");
        }

        return parentPaths;
    }
}