/*
* Copyright (C) 2010-2016 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 org.waterforpeople.mapping.dataexport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.waterforpeople.mapping.app.gwt.client.survey.QuestionDto;
import org.waterforpeople.mapping.app.gwt.client.survey.QuestionGroupDto;
import org.waterforpeople.mapping.app.gwt.client.survey.SurveyDto;
import org.waterforpeople.mapping.app.gwt.client.survey.SurveyGroupDto;
import org.waterforpeople.mapping.app.gwt.server.survey.SurveyServiceImpl;
import org.waterforpeople.mapping.app.util.DtoMarshaller;
import org.waterforpeople.mapping.dataexport.service.BulkDataServiceClient;
import com.gallatinsystems.framework.domain.BaseDomain;
import com.gallatinsystems.framework.gwt.dto.client.BaseDto;
import com.gallatinsystems.survey.dao.QuestionDao;
import com.gallatinsystems.survey.dao.QuestionGroupDao;
import com.gallatinsystems.survey.dao.SurveyDAO;
import com.gallatinsystems.survey.dao.SurveyGroupDAO;
import com.gallatinsystems.survey.domain.Question;
import com.gallatinsystems.survey.domain.QuestionGroup;
import com.gallatinsystems.survey.domain.Survey;
import com.gallatinsystems.survey.domain.Survey.Status;
import com.gallatinsystems.survey.domain.SurveyGroup;
import com.gallatinsystems.survey.domain.SurveyGroup.ProjectType;
public class SurveyReplicationImporter {
/**
* copies one surveyGroup "Survey" remaps all ids to make merging two instances safe
*
* @param sourceBase
* @param groupId
* @param apiKey
*/
public void importOneGroup(String sourceBase, long surveyId, String apiKey) {
SurveyGroupDAO sgDao = new SurveyGroupDAO();
SurveyDAO sDao = new SurveyDAO();
QuestionGroupDao qgDao = new QuestionGroupDao();
QuestionDao qDao = new QuestionDao();
System.out
.println("Importing survey " + surveyId + " with id remapping from " + sourceBase);
int count_sg = 0, count_s = 0, count_qg = 0, count_q = 0;
try {
// First, find which group the survey is in
List<SurveyGroup> allGroups = fetchSurveyGroups(sourceBase, apiKey);
System.out.println(" scanning " + allGroups.size() + " survey groups");
for (SurveyGroup sg : allGroups) {
System.out.println(" surveygroup: " + sg.getKey().getId() + " " + sg.getName()
+ ":" + sg.getCode());
count_sg++;
if (sg.getProjectType() != ProjectType.PROJECT) {
continue; // skip looking in folders
}
boolean thisIsTheGroup = false;
List<Survey> allSurveys = fetchSurveys(sg.getKey().getId(), sourceBase, apiKey);
for (Survey s0 : allSurveys) {
if (s0.getKey().getId() == surveyId) {
thisIsTheGroup = true; // Found it!
break;
}
}
if (thisIsTheGroup) {
System.out.println(" copying group with " + allSurveys.size() + " surveys");
sg.setParentId(0L); // go in root folder
sg.setPath(""); // not used anymore
List<Long> nai = new ArrayList<Long>(1);
nai.add(0L);
sg.setAncestorIds(nai);
sg.getKey().getId();
sg.setKey(null); // want new key
sgDao.save(sg);
long newId = sg.getKey().getId();
// if set, sg.newLocaleSurveyId is now wrong
// Now copy everything inside it
// First, surveys (may be more than one for a monitored survey)
for (Survey s : allSurveys) {
System.out.println(" survey:" + s.getKey().getId() + " " + s.getCode());
long oldSurveyId = s.getKey().getId();
s.setKey(null);// want a new key
List<Long> nai2 = new ArrayList<Long>(2);
nai2.add(0L);
nai2.add(newId);
s.setAncestorIds(nai2);
s.setSurveyGroupId(newId);
s.setPath("");
s.setStatus(Status.NOT_PUBLISHED); // not downloadable yet
s.setVersion(1.0);
sDao.save(s);
long newSurveyId = s.getKey().getId();
// Fix up newLocaleSurveyId
if (sg.getNewLocaleSurveyId() != null
&& sg.getNewLocaleSurveyId() == oldSurveyId) {
System.out.println(" registration form id fixup :" + oldSurveyId
+ " -> " + newSurveyId);
sg.setNewLocaleSurveyId(newSurveyId);
sgDao.save(sg);
}
count_s++;
// The question groups
HashMap<Long, Long> qMap = new HashMap<Long, Long>(); // used to fix up
// dependency
// references
List<QuestionGroup> allQgs = fetchQuestionGroups(oldSurveyId, sourceBase,
apiKey);
for (QuestionGroup qg : allQgs) {
System.out.println(" qg:" + qg.getKey().getId() + " "
+ qg.getCode());
long oldQgId = qg.getKey().getId();
qg.setKey(null); // want a new key
qg.setSurveyId(newSurveyId);
qg.setPath("");
qgDao.save(qg);
long newQgId = qg.getKey().getId();
// Now the questions
for (Question q : fetchQuestions(oldQgId, sourceBase, apiKey)) {
System.out.println(" q:" + q.getKey().getId() + " "
+ q.getText());
q.setPath("");
long oldQId = q.getKey().getId();
q.setKey(null); // want a new key
qDao.save(q, newQgId); // options and other details are saved w the
// new question id
long newQId = q.getKey().getId();
qMap.put(oldQId, newQId);
count_q++;
}
count_qg++;
}
// Now we know all question ids, so we can fix up their dependencies
System.out.println(" q depependency fixup pass");
for (long qid : qMap.values()) {
Question q = qDao.getByKey(qid); // need no details
if (q == null) {
System.out.println(" q not found:" + qid);
continue;
}
if (q.getDependentFlag() && q.getDependentQuestionId() != null) {
Long updatedId = qMap.get(q.getDependentQuestionId());
if (updatedId != null) {
System.out.println(" q:" + q.getText());
System.out.println(" dep fixup :"
+ q.getDependentQuestionId() + " -> " + updatedId);
q.setDependentQuestionId(updatedId);
qDao.save(q, q.getQuestionGroupId());
}
}
}
}
break; // we can stop looking for the survey group
}
}
System.out.println("Survey import complete after " + count_sg + " groups scanned; "
+ count_s + " surveys, " + count_qg + " question groups, " + count_q
+ " questions copied. ");
} catch (Exception e) {
e.printStackTrace();
}
}
// surveyId == null copies all surveys, all forms
public void executeImport(String sourceBase, Long surveyId, String apiKey) {
if (surveyId != null) {
importOneGroup(sourceBase, surveyId, apiKey);
return;
}
SurveyGroupDAO sgDao = new SurveyGroupDAO();
SurveyDAO sDao = new SurveyDAO();
// HashMap<Long,Long> NewSurveyGroupIds = new HashMap<Long,Long>();
QuestionGroupDao qgDao = new QuestionGroupDao();
QuestionDao qDao = new QuestionDao();
// HashMap<Long,Long> NewSurveyIds = new HashMap<Long,Long>();
boolean hasFoundSurvey = false;
try {
List<SurveyGroup> allGroups = fetchSurveyGroups(sourceBase, apiKey);
for (SurveyGroup sg : allGroups) {
System.out.println("surveygroup: " + sg.getName() + ":"
+ sg.getCode());
if (surveyId == null) {// All surveys, so copy all groups, too
sgDao.save(sg);
}
for (Survey s : fetchSurveys(sg.getKey().getId(), sourceBase, apiKey)) {
System.out.println(" survey:" + s.getCode());
if (surveyId != null && surveyId.equals(s.getKey().getId())) {
// walk the ancestor id array to save all the ancestral groups
for (Long ancestor : s.listAncestorIds()) {
if (ancestor != 0 && ancestor != sg.getKey().getId()) {// Not root, not
// parent
// Unsaved intermediate ancestor
for (SurveyGroup potentialAncestor : allGroups) {
if (potentialAncestor.getKey().getId() == ancestor) {
sgDao.save(potentialAncestor);
}
}
}
}
sgDao.save(sg);// Immediate ancestor
sDao.save(s);
hasFoundSurvey = true;
} else if (surveyId != null) {
// if survey ID is not null but isn't matching, skip to
// next survey
continue;
} else {// All surveys
sDao.save(s);
}
for (QuestionGroup qg : fetchQuestionGroups(s.getKey()
.getId(), sourceBase, apiKey)) {
System.out.println(" qg:" + qg.getCode());
qgDao.save(qg);
for (Question q : fetchQuestions(qg.getKey().getId(),
sourceBase, apiKey)) {
System.out.println(" q" + q.getText());
qDao.save(q, qg.getKey().getId());
}
}
if (hasFoundSurvey) {
// if we've saved the survey we're looking for, we're
// done
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public List<SurveyGroup> fetchSurveyGroups(String serverBase, String apiKey)
throws Exception {
List<SurveyGroupDto> sgDtoList = BulkDataServiceClient
.fetchSurveyGroups(serverBase, apiKey);
List<SurveyGroup> sgList = new ArrayList<SurveyGroup>();
return copyAndCreateList(sgList, sgDtoList, SurveyGroup.class);
}
public List<Survey> fetchSurveys(Long surveyGroupId, String serverBase, String apiKey)
throws Exception {
List<SurveyDto> surveyDtoList = BulkDataServiceClient.fetchSurveys(
surveyGroupId, serverBase, apiKey);
List<Survey> surveyList = new ArrayList<Survey>();
return copyAndCreateList(surveyList, surveyDtoList, Survey.class);
}
public List<QuestionGroup> fetchQuestionGroups(Long surveyId,
String serverBase, String apiKey) throws Exception {
List<QuestionGroupDto> qgDtoList = BulkDataServiceClient
.fetchQuestionGroups(serverBase, surveyId.toString(), apiKey);
List<QuestionGroup> qgList = new ArrayList<QuestionGroup>();
return copyAndCreateList(qgList, qgDtoList, QuestionGroup.class);
}
public List<Question> fetchQuestions(Long questionGroupId, String serverBase, String apiKey)
throws Exception {
List<QuestionDto> qgDtoList = BulkDataServiceClient.fetchQuestions(
serverBase, questionGroupId, apiKey);
List<Question> qList = new ArrayList<Question>();
SurveyServiceImpl ssi = new SurveyServiceImpl();
for (QuestionDto dto : qgDtoList) {
QuestionDto dtoDetail = null;
for (int i = 0; i < 3; i++) {
try {
dtoDetail = BulkDataServiceClient
.loadQuestionDetails(serverBase, dto.getKeyId(), apiKey);
break;
} catch (IOException iex) {
System.out.print("Retrying because of timeout.");
}
}
Question q = ssi.marshalQuestion(dtoDetail);
qList.add(q);
}
return qList;
}
public static <T extends BaseDomain, U extends BaseDto> List<T> copyAndCreateList(
List<T> canonicalList, List<U> dtoList, Class<T> clazz) {
for (U dto : dtoList) {
T canonical = null;
try {
canonical = clazz.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DtoMarshaller.copyToCanonical(canonical, dto);
if (canonical instanceof Survey && dto instanceof SurveyDto) {
Survey s = (Survey) canonical;
SurveyDto d = (SurveyDto) dto;
// overwrite status for published surveys to unpublished
if (Survey.Status.PUBLISHED.equals(s.getStatus())) {
s.setStatus(Survey.Status.NOT_PUBLISHED);
}
// mismatch in SurveyDto and Survey property names
s.setDesc(d.getDescription());
}
canonicalList.add(canonical);
}
return canonicalList;
}
}