package org.openlca.app.navigation.actions; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.openlca.app.App; import org.openlca.app.M; import org.openlca.app.cloud.CloudUtil; import org.openlca.app.cloud.JsonLoader; import org.openlca.app.cloud.index.Diff; import org.openlca.app.cloud.index.DiffIndex; import org.openlca.app.cloud.ui.DiffDialog; import org.openlca.app.cloud.ui.FetchNotifierMonitor; import org.openlca.app.cloud.ui.commits.CommitEntryDialog; import org.openlca.app.cloud.ui.commits.HistoryView; import org.openlca.app.cloud.ui.compare.json.JsonUtil; import org.openlca.app.cloud.ui.diff.DiffNode; import org.openlca.app.cloud.ui.diff.DiffNodeBuilder; import org.openlca.app.cloud.ui.diff.DiffResult; import org.openlca.app.cloud.ui.diff.DiffResult.DiffResponse; import org.openlca.app.db.Database; import org.openlca.app.navigation.DatabaseElement; import org.openlca.app.navigation.INavigationElement; import org.openlca.app.navigation.Navigator; import org.openlca.app.util.Error; import org.openlca.app.util.Info; import org.openlca.app.util.UI; import org.openlca.cloud.api.RepositoryClient; import org.openlca.cloud.model.data.Commit; import org.openlca.cloud.model.data.Dataset; import org.openlca.cloud.model.data.FetchRequestData; import org.openlca.cloud.model.data.FileReference; import org.openlca.cloud.util.WebRequests.WebRequestException; import org.openlca.core.model.Process; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; class CloudFetchAction extends Action implements INavigationAction { private Logger log = LoggerFactory.getLogger(CloudFetchAction.class); private RepositoryClient client; private DiffIndex index; public CloudFetchAction() { setText(M.Fetch); } @Override public void run() { Runner runner = new Runner(); runner.run(); if (runner.error != null) { log.error("Error during fetch action", runner.error); Error.showBox(runner.error.getMessage()); } Navigator.refresh(); HistoryView.refresh(); } private class Runner { private List<Commit> commits; private List<DiffResult> differences; private Exception error; private DiffNode root; public void run() { App.runWithProgress(M.FetchingCommits, this::fetchCommits); boolean doContinue = showCommitEntries(); if (!doContinue) return; App.runWithProgress(M.FetchingChanges, this::requestFetch); doContinue = showDifferences(); if (!doContinue) return; fetchData(); if (error != null) return; } private void fetchCommits() { try { commits = client.fetchNewCommitHistory(); } catch (Exception e) { error = e; } } private boolean showCommitEntries() { if (error != null) return false; if (commits.isEmpty()) { showNoChangesBox(); return false; } CommitEntryDialog dialog = new CommitEntryDialog(commits, client); if (dialog.open() != IDialogConstants.OK_ID) return false; return true; } private void requestFetch() { try { Set<FetchRequestData> descriptors = client.requestFetch(); differences = createDifferences(descriptors); root = new DiffNodeBuilder(client.getConfig().getDatabase(), index).build(differences); } catch (Exception e) { error = e; } } private boolean showDifferences() { if (error != null) return false; if (root == null) return false; if (root.children.isEmpty()) return true; JsonLoader loader = CloudUtil.getJsonLoader(client); DiffDialog dialog = new DiffDialog(root, loader); if (dialog.open() != IDialogConstants.OK_ID) return false; return true; } private void fetchData() { Set<FileReference> toFetch = new HashSet<>(); Map<Dataset, JsonObject> mergedData = new HashMap<>(); for (DiffResult result : differences) { if (result.getType() == DiffResponse.NONE) continue; Dataset dataset = result.getDataset(); JsonObject data = result.getMergedData(); String type = JsonUtil.getString(data, "@type"); if (Process.class.getSimpleName().equals(type)) { joinExchanges(data); } if (data != null) { mergedData.put(dataset, data); } else { toFetch.add(dataset.asFileReference()); } } try { Database.getIndexUpdater().disable(); ProgressMonitorDialog dialog = new ProgressMonitorDialog(UI.shell()); dialog.run(true, false, new IRunnableWithProgress() { @Override public void run(IProgressMonitor m) throws InvocationTargetException, InterruptedException { try { m.beginTask(M.Preparing, IProgressMonitor.UNKNOWN); FetchNotifierMonitor monitor = new FetchNotifierMonitor(m, M.FetchingData); client.fetch(toFetch, mergedData, monitor); monitor.beginTask("#Indexing datasets", differences.size()); FetchIndexHelper.index(differences, index, (e) -> monitor.worked()); monitor.done(); } catch (WebRequestException e) { throw new InvocationTargetException(e); } } }); } catch (Exception e) { error = e; } finally { Database.getIndexUpdater().enable(); } } // for ease of display, the exchanges list was split into inputs and // outputs, these two lists need to be merged private void joinExchanges(JsonObject data) { JsonArray exchanges = new JsonArray(); JsonArray inputs = data.getAsJsonArray("inputs"); JsonArray outputs = data.getAsJsonArray("outputs"); if (inputs != null) { for (JsonElement elem : inputs) { JsonObject e = elem.getAsJsonObject(); exchanges.add(e); } } if (outputs != null) { for (JsonElement elem : outputs) { JsonObject e = elem.getAsJsonObject(); exchanges.add(e); } } data.remove("inputs"); data.remove("outputs"); data.add("exchanges", exchanges); } private void showNoChangesBox() { Info.showBox(M.UpToDate); } private List<DiffResult> createDifferences(Set<FetchRequestData> remotes) { List<DiffResult> differences = new ArrayList<>(); for (FetchRequestData identifier : remotes) { Diff local = index.get(identifier.refId); differences.add(new DiffResult(identifier, local)); } return differences; } } @Override public boolean accept(INavigationElement<?> element) { if (!(element instanceof DatabaseElement)) return false; client = Database.getRepositoryClient(); if (client == null) return false; index = Database.getDiffIndex(); return true; } @Override public boolean accept(List<INavigationElement<?>> elements) { return false; } }