blob: e668261d88d3767871ce346f68a2e86b0d7812da [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2014, 2016 CEA LIST, Christian W. Damus, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus - bug 496439
* Vincent Lorenzo - bug 496176
*****************************************************************************/
package org.eclipse.papyrus.interoperability.common.transformation;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.papyrus.interoperability.common.Activator;
import org.eclipse.papyrus.interoperability.common.MigrationParameters.ThreadConfig;
import org.eclipse.papyrus.interoperability.common.internal.Schedulable;
import org.eclipse.papyrus.interoperability.common.internal.Scheduler;
import org.eclipse.papyrus.interoperability.common.internal.TransformationWrapper;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.statushandlers.StatusManager;
/**
* Executes a batch of {@link ImportTransformation}s, then restores the dependencies (References)
* between each other
*
* @author Vincent Lorenzo
*
*/
public abstract class AbstractImportTransformationLauncher implements IImportTransformationLauncher {
// Nano to Second
protected final static long SECOND = 1000 * 1000 * 1000;
// Nano to Milliseconds
protected final static long MILLIS = 1000 * 1000;
protected final ThreadConfig config;
protected final Control baseControl;
/**
* Own execution time, in nano-seconds. Doesn't take individual transformation's exec
* time into account. Also ignores the time when Blocking user Dialogs are opened
*/
protected long ownExecutionTime;
/**
* Own loading time (For initial model loading)
*/
protected long ownLoadingTime;
/**
* Own cumulated execution time for repairing stereotypes
*/
protected long ownRepairStereotypesTime;
/**
* Own cumulated execution time for repairing libraries
*/
protected long ownRepairLibrariesTime;
/**
* Own execution time for resolving all matches for broken profiles/libraries
*/
protected long resolveAllDependencies;
/**
* The top-level job for this transformation
*/
protected Job importDependenciesJob;
/**
* Total time for all invidivual transformations to complete. Since they are executed in parallel,
* this may be different from their cumulated execution time (Unless a single thread is used)
*/
protected long transformationsExecutionTime = 0L;
protected IDependencyAnalysisHelper analysisHelper;
public AbstractImportTransformationLauncher(ThreadConfig config) {
this(config, null);
}
public AbstractImportTransformationLauncher(ThreadConfig config, Control baseControl) {
this.config = config;
this.baseControl = baseControl;
}
/**
* Executes the transformation (Asynchronous)
*
* @param urisToImport
*/
public void run(List<URI> urisToImport) {
List<IImportTransformation> transformations = new LinkedList<IImportTransformation>();
analysisHelper = createDependencyAnalysisHelper(config);
for (URI uri : urisToImport) {
IImportTransformation transformation = createTransformation(uri, config, analysisHelper);
transformations.add(transformation);
}
// Always use the batch launcher, even if there is only 1 transformation (Bug 455012)
importModels(transformations);
}
protected abstract IDependencyAnalysisHelper createDependencyAnalysisHelper(final ThreadConfig config);
protected abstract IImportTransformation createTransformation(URI transformationURI, final ThreadConfig config, final IDependencyAnalysisHelper analysisHelper);
public static final String IMPORT_MODELS_JOB_NAME = "Import Models"; // $NON-NLS-0$
/**
* Start a Job and delegate to {@link #importModels(IProgressMonitor, List)}
*
* @param transformations
*/
protected void importModels(final List<IImportTransformation> transformations) {
importDependenciesJob = new Job(IMPORT_MODELS_JOB_NAME) {
@Override
protected IStatus run(IProgressMonitor monitor) {
IStatus result = AbstractImportTransformationLauncher.this.importModels(monitor, transformations);
if (monitor.isCanceled()) {
return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, "Operation Canceled");
}
long cumulatedLoadingTime = 0L;
long cumulatedTransformationTime = 0L;
long cumulatedHandleDanglingTime = 0L;
long cumulatedImportExtensionsTime = 0L;
for (IImportTransformation transformation : transformations) {
cumulatedLoadingTime += transformation.getLoadingTime();
cumulatedImportExtensionsTime += transformation.getImportExtensionsTime();
cumulatedHandleDanglingTime += transformation.getHandleDanglingRefTime();
cumulatedTransformationTime += transformation.getExecutionTime();
log("Import " + transformation.getModelName());
log("First phase (0-50%):");
log("\tTotal loading time: " + timeFormat(transformation.getLoadingTime()));
log("\tTotal Import Extensions time: " + timeFormat(transformation.getImportExtensionsTime()));
log("\tTotal Handle Dangling References time: " + timeFormat(transformation.getHandleDanglingRefTime()));
log("\tTotal execution time: " + timeFormat(transformation.getExecutionTime()));
Long loadingTime = loadingTimeV2.get(transformation);
Long repairProxiesTime = proxiesTime.get(transformation);
Long repairStereoTime = stereoTime.get(transformation);
Long totalPhase2 = totalTimeV2.get(transformation);
log("Second phase (50-100%):");
log("\tTotal loading time: " + timeFormat(loadingTime));
log("\tTotal fix proxies time: " + timeFormat(repairProxiesTime));
log("\tTotal fix stereotypes time: " + timeFormat(repairStereoTime));
log("\tTotal execution time: " + timeFormat(totalPhase2));
log("Total");
log("\tTotal execution time: " + timeFormat(transformation.getExecutionTime() + (totalPhase2 == null ? 0 : totalPhase2)));
log("\n");
}
int nbThreads = Math.max(1, config.getMaxThreads());
log("First phase (0-50%) / " + nbThreads + " Threads");
log("\tCumulated Transformation Time: " + timeFormat(cumulatedTransformationTime));
log("\tCumulated Loading Time: " + timeFormat(cumulatedLoadingTime));
log("\tCumulated Handle Dangling Refs Time: " + timeFormat(cumulatedHandleDanglingTime));
log("\tCumulated Import Extensions Time: " + timeFormat(cumulatedImportExtensionsTime));
log("\tTotal Transformation Time: " + timeFormat(transformationsExecutionTime));
log("Second phase (50-100%) / " + nbThreads + " Threads");
log("\tTotal Handle all Dangling References: " + timeFormat(resolveAllDependencies));
log("\tCumulated Loading Time: " + timeFormat(ownLoadingTime));
log("\tCumulated Fix Libraries Time: " + timeFormat(ownRepairLibrariesTime));
log("\tCumulated Fix Stereotypes Time: " + timeFormat(ownRepairStereotypesTime));
log("\tTotal Fix Dependencies Time: " + timeFormat(ownExecutionTime));
log("Total");
log("\tCumulated Total time: " + timeFormat(ownExecutionTime + cumulatedTransformationTime));
log("\tTotal time: " + timeFormat(ownExecutionTime + transformationsExecutionTime));
log("Import Complete");
log("");
return result;
}
};
importDependenciesJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
MultiStatus multiStatus = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, "", null);
multiStatus.merge(event.getResult());
for (IImportTransformation transformation : transformations) {
multiStatus.merge(transformation.getStatus());
}
int severity = multiStatus.getSeverity();
String message;
switch (severity) {
case IStatus.OK:
message = "The selected models have been successfully imported";
break;
case IStatus.CANCEL:
message = "Operation canceled";
break;
case IStatus.WARNING:
message = "The selected models have been imported; some warnings have been reported";
break;
default:
message = "Some errors occurred during model import";
break;
}
handle(new MultiStatus(Activator.PLUGIN_ID, severity, multiStatus.getChildren(), message, null));
}
protected void handle(final IStatus status) {
if (baseControl == null) {
int severity = status.getSeverity();
if (severity == IStatus.OK || severity == IStatus.CANCEL) {
return;
}
StatusManager.getManager().handle(status, StatusManager.LOG);
return;
}
Display display = baseControl.getDisplay();
if (status.getSeverity() == IStatus.OK) {
display.asyncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openInformation(baseControl.getShell(), "Import models", status.getMessage());
}
});
} else if (status.getSeverity() == IStatus.CANCEL) {
display.asyncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openInformation(baseControl.getShell(), "Import models", status.getMessage());
}
});
} else {
StatusManager.getManager().handle(status, StatusManager.BLOCK);
}
}
});
importDependenciesJob.setUser(true);
importDependenciesJob.schedule();
}
protected void log(String message) {
System.out.println(message);
MessageConsole console = getConsole();
MessageConsoleStream out = console.newMessageStream();
out.println(message);
}
protected static final String CONSOLE_NAME = "Model Import Results"; // The name is both the ID and the Label
protected MessageConsole getConsole() {
ConsolePlugin plugin = ConsolePlugin.getDefault();
IConsoleManager consoleManager = plugin.getConsoleManager();
IConsole[] existing = consoleManager.getConsoles();
for (int i = 0; i < existing.length; i++) {
if (CONSOLE_NAME.equals(existing[i].getName())) {
return (MessageConsole) existing[i];
}
}
// no console found, so create a new one
MessageConsole rsaConsole = new MessageConsole(CONSOLE_NAME, null);
consoleManager.addConsoles(new IConsole[] { rsaConsole });
return rsaConsole;
}
protected String timeFormat(Long nano) {
if (nano == null) {
return "?"; // FIXME: crash?
}
long seconds = nano / SECOND;
if (seconds < 1) {
long millis = nano / MILLIS;
return String.format("%s ms", millis);
}
return String.format("%d:%02d:%02d", seconds / 3600, (seconds % 3600) / 60, (seconds % 60));
}
/**
* Schedules all the individual transformations, wait for completion, then
* call {@link #handleModelDependencies(List, IProgressMonitor)}
*
* @param monitor
* @param transformations
* @return
*/
protected IStatus importModels(IProgressMonitor monitor, List<IImportTransformation> transformations) {
long begin = System.nanoTime();
monitor.setTaskName("Waiting for import tasks to complete...");
int numTasks = transformations.size() * 2; // For each transformation: wait for completion, then handle dependencies
monitor.beginTask("Importing Models...", numTasks);
List<Schedulable> tasks = new LinkedList<Schedulable>();
for (IImportTransformation transformation : transformations) {
tasks.add(new TransformationWrapper(transformation));
}
Scheduler scheduler = new Scheduler(config.getMaxThreads());
scheduler.schedule(monitor, tasks);
long end = System.nanoTime();
transformationsExecutionTime = end - begin;
if (monitor.isCanceled()) {
return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, "Operation canceled");
}
handleModelDependencies(transformations, monitor);
return Status.OK_STATUS;
}
protected void handleModelDependencies(List<IImportTransformation> transformations, IProgressMonitor monitor) {
// TODO, seem not required for Rpy import
}
final protected Map<IImportTransformation, Long> loadingTimeV2 = new HashMap<IImportTransformation, Long>();
final protected Map<IImportTransformation, Long> proxiesTime = new HashMap<IImportTransformation, Long>();
final protected Map<IImportTransformation, Long> stereoTime = new HashMap<IImportTransformation, Long>();
final protected Map<IImportTransformation, Long> totalTimeV2 = new HashMap<IImportTransformation, Long>();
/** Mainly for test purpose */
public void waitForCompletion() throws Exception {
importDependenciesJob.join();
}
/** Mainly for test purpose */
public IStatus getResult() {
return importDependenciesJob.getResult();
}
}