package gov.nasa.jpl.mbee.mdk.mms.sync.manual;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.nomagic.magicdraw.core.Application;
import com.nomagic.magicdraw.core.Project;
import com.nomagic.task.ProgressStatus;
import com.nomagic.task.RunnableWithProgress;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Element;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Package;
import gov.nasa.jpl.mbee.mdk.api.incubating.MDKConstants;
import gov.nasa.jpl.mbee.mdk.api.incubating.convert.Converters;
import gov.nasa.jpl.mbee.mdk.util.Utils;
import gov.nasa.jpl.mbee.mdk.validation.ValidationSuite;
import gov.nasa.jpl.mbee.mdk.mms.MMSUtils;
import gov.nasa.jpl.mbee.mdk.http.ServerException;
import gov.nasa.jpl.mbee.mdk.mms.validation.BranchValidator;
import gov.nasa.jpl.mbee.mdk.mms.validation.ElementValidator;
import gov.nasa.jpl.mbee.mdk.mms.validation.ProjectValidator;
import gov.nasa.jpl.mbee.mdk.util.Pair;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* Created by igomes on 9/26/16.
*/
public class ManualSyncRunner implements RunnableWithProgress {
private final Collection<Element> rootElements;
private final Project project;
private final int depth;
// TODO Move me to common sync pre-conditions @donbot
private ValidationSuite validationSuite = new ValidationSuite("Manual Sync Validation");
private ElementValidator elementValidator;
public ManualSyncRunner(Collection<Element> rootElements, Project project, int depth) {
this.rootElements = rootElements;
this.project = project;
this.depth = depth;
}
@Override
public void run(ProgressStatus progressStatus) {
progressStatus.setDescription("Validating sync pre-conditions");
progressStatus.setIndeterminate(true);
ProjectValidator pv = new ProjectValidator(project);
pv.validate();
if (pv.hasErrors()) {
Application.getInstance().getGUILog().log("[ERROR] Manual sync can not complete and will be skipped.");
return;
}
if (pv.getValidationSuite().hasErrors()) {
Utils.displayValidationWindow(project, pv.getValidationSuite(), "Sync Pre-Condition Validation");
return;
}
if (project.isRemote()) {
BranchValidator bv = new BranchValidator(project);
bv.validate(null, false);
if (bv.hasErrors()) {
Application.getInstance().getGUILog().log("[ERROR] Manual sync can not complete and will be skipped.");
return;
}
if (bv.getValidationSuite().hasErrors()) {
Utils.displayValidationWindow(project, bv.getValidationSuite(), "Sync Pre-Condition Validation");
return;
}
}
progressStatus.setDescription("Processing and querying for " + rootElements.size() + " " + ((depth != 0) ? "root " : "") + "element" + (rootElements.size() != 1 ? "s" : ""));
progressStatus.setIndeterminate(false);
progressStatus.setMax(rootElements.size());
progressStatus.setCurrent(0);
List<Pair<Element, ObjectNode>> clientElements = new ArrayList<>(rootElements.size());
Collection<File> responseFiles = new ArrayList<>(3);
for (Element element : rootElements) {
collectClientElementsRecursively(project, element, depth, clientElements);
try {
File responseFile = collectServerElementsRecursively(project, element, depth, progressStatus);
if (responseFile != null) {
responseFiles.add(responseFile);
}
if (element == project.getPrimaryModel() && depth != 0) {
// scan of initial return for holding bin is expensive. assume it's not there and request anyway
if (progressStatus.isCancel()) {
Application.getInstance().getGUILog().log("[INFO] Manual sync cancelled by user. Aborting.");
return;
}
responseFile = collectServerHoldingBinElementsRecursively(project, depth - 1, progressStatus);
if (responseFile != null) {
responseFiles.add(responseFile);
}
if (progressStatus.isCancel()) {
Application.getInstance().getGUILog().log("[INFO] Manual sync cancelled by user. Aborting.");
return;
}
responseFile = collectServerModuleElementsRecursively(project, 0, progressStatus);
if (responseFile != null) {
responseFiles.add(responseFile);
}
}
} catch (ServerException | URISyntaxException | IOException e) {
Application.getInstance().getGUILog().log("[ERROR] Exception occurred while getting elements from the server. Aborting manual sync.");
e.printStackTrace();
validationSuite = null;
return;
}
if (responseFiles.isEmpty()) {
if (!progressStatus.isCancel()) {
Application.getInstance().getGUILog().log("[ERROR] Failed to get elements from the server. Aborting manual sync.");
}
validationSuite = null;
return;
}
progressStatus.increase();
}
if (progressStatus.isCancel()) {
Application.getInstance().getGUILog().log("[INFO] Manual sync cancelled by user. Aborting.");
return;
}
elementValidator = new ElementValidator("Element Validation", clientElements, null, project, responseFiles);
elementValidator.run(progressStatus);
}
private static void collectClientElementsRecursively(Project project, Element element, int depth, List<Pair<Element, ObjectNode>> elements) {
ObjectNode jsonObject = Converters.getElementToJsonConverter().apply(element, project);
if (jsonObject == null) {
return;
}
elements.add(new Pair<>(element, jsonObject));
if (depth-- != 0) {
for (Element elementChild : element.getOwnedElement()) {
collectClientElementsRecursively(project, elementChild, depth, elements);
}
}
if (element.equals(project.getPrimaryModel())) {
List<Package> attachedModels = project.getModels();
attachedModels.remove(project.getPrimaryModel());
attachedModels.forEach(attachedModel -> collectClientElementsRecursively(project, attachedModel, 0, elements));
}
}
private static File collectServerElementsRecursively(Project project, Element element, int depth, ProgressStatus progressStatus)
throws ServerException, IOException, URISyntaxException {
String id = Converters.getElementToIdConverter().apply(element);
Collection<String> elementIds = new ArrayList<>(1);
elementIds.add(id);
return MMSUtils.getElementsRecursively(project, elementIds, depth, progressStatus);
}
private static File collectServerModuleElementsRecursively(Project project, int depth, ProgressStatus progressStatus)
throws ServerException, IOException, URISyntaxException {
Collection<Element> attachedModels = new ArrayList<>(project.getModels());
attachedModels.remove(project.getPrimaryModel());
Collection<String> attachedModelIds = attachedModels.stream().map(Converters.getElementToIdConverter()).filter(amId -> amId != null).collect(Collectors.toList());
return MMSUtils.getElements(project, attachedModelIds, null);
}
private static File collectServerHoldingBinElementsRecursively(Project project, int depth, ProgressStatus progressStatus)
throws ServerException, IOException, URISyntaxException {
String holdingBinId = MDKConstants.HOLDING_BIN_ID_PREFIX + Converters.getIProjectToIdConverter().apply(project.getPrimaryProject());
return MMSUtils.getElementRecursively(project, holdingBinId, depth, progressStatus);
}
public ValidationSuite getValidationSuite() {
if (validationSuite == null) {
return null;
}
return validationSuite.hasErrors() ? validationSuite : (elementValidator != null ? elementValidator.getValidationSuite() : null);
}
}