blob: 2f0b655fe8e8d38177233f407ceab5d3ae47b758 [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2015-2021 Robert Bosch GmbH and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.amalthea.converters.ui.handlers;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Named;
import org.eclipse.app4mc.amalthea.converters.common.MigrationHelper;
import org.eclipse.app4mc.amalthea.converters.common.MigrationInputFile;
import org.eclipse.app4mc.amalthea.converters.common.MigrationProcessor;
import org.eclipse.app4mc.amalthea.converters.common.MigrationSettings;
import org.eclipse.app4mc.amalthea.converters.ui.dialog.ModelMigrationDialog;
import org.eclipse.app4mc.amalthea.converters.ui.jobs.ModelMigrationJob;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.di.extensions.Service;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.widgets.Shell;
@SuppressWarnings("restriction")
public class AmaltheaModelMigrationHandler {
private static final String MODEL_MIGRATION = "AMALTHEA Model Migration";
private static final String SIMPLE_MIGRATION = "simplemigration";
/**
* Executes the migration in an Eclipse UI. Opens dialogs and uses the jobs
* framework for asynchronous execution.
*
* @param shell The current Shell.
* @param migrationProcessor The {@link MigrationProcessor} service that
* performs the migration.
* @param selection The current active selection in the workspace.
* @param executionContext Optional parameter that can be used to trigger a
* simple migration if set to "simplemigration".
* @param modelEditorVersion The model version that is supported by the
* available editor. Can be <code>null</code> which
* leads to using the latest supported version by the
* migration component.
*/
@Execute
public void execute(
Shell shell,
@Service MigrationProcessor migrationProcessor,
@Named(IServiceConstants.ACTIVE_SELECTION) ISelection selection,
@Optional @Named("executioncontext") String executionContext,
@Optional @Named("APP4MC_MODEL_VERSION") String modelEditorVersion) {
if (selection instanceof TreeSelection) {
try (MigrationSettings migrationSettings = new MigrationSettings()) {
ArrayList<File> inputModels = new ArrayList<>();
IProject iProject = getProjectFromSelection((TreeSelection) selection, shell);
if (iProject != null) {
String path = iProject.getLocation().toOSString();
File file = new File(path);
migrationSettings.setProject(file);
} else {
return;
}
IContainer selectedContainer = collectInput((TreeSelection) selection, inputModels, shell);
if (modelEditorVersion != null) {
migrationSettings.setMigrationModelVersion(modelEditorVersion);
}
try {
List<MigrationInputFile> modelFiles = MigrationHelper.populateModels(inputModels, migrationSettings);
migrationSettings.getMigModelFiles().addAll(modelFiles);
} catch (Exception e) {
MessageDialog.openError(shell, MODEL_MIGRATION,
"Failed to load model files: " + e.getLocalizedMessage());
return;
}
if (isSimpleMigration(executionContext) && migrationSettings.getMigModelFiles().size() == 1) {
// for simple migration perform simple settings and start migration directly
// set the file parent folder as output location to convert the file at source
MigrationInputFile migrationInputFile = migrationSettings.getMigModelFiles().get(0);
migrationSettings.setOutputDirectoryLocation(migrationInputFile.getOriginalFile().getParent());
// ensure a backup is created
migrationSettings.setCreateBackupFile(true);
//now call migration job to migrate the file to latest Amalthea version
ModelMigrationJob migrationJob = new ModelMigrationJob(
MODEL_MIGRATION,
migrationProcessor,
migrationSettings,
iProject);
migrationJob.setUser(true);
migrationJob.schedule();
} else {
// open dialog so the user can configure the settings
ModelMigrationDialog dialog = new ModelMigrationDialog(shell, migrationProcessor, migrationSettings, iProject);
dialog.setSelectedContainer(selectedContainer);
dialog.open();
}
}
}
}
private IProject getProjectFromSelection(TreeSelection selection, Shell shell) {
TreePath[] paths = selection.getPaths();
String projectSegment = null;
IProject iProject = null;
for (TreePath treePath : paths) {
Object firstSegment = treePath.getFirstSegment();
if (projectSegment == null) {
projectSegment = firstSegment.toString();
iProject = ((IAdaptable) firstSegment).getAdapter(IProject.class);
if (iProject == null) {
// if the first segment could not be transformed to an IProject, try the second segment
// could happen in case of enabled WorkingSets
firstSegment = treePath.getSegment(1);
projectSegment = firstSegment.toString();
iProject = ((IAdaptable) firstSegment).getAdapter(IProject.class);
}
}
else if (!projectSegment.equals(firstSegment.toString())) {
MessageDialog.openError(shell, MODEL_MIGRATION,
"Migration across multiple projects is not supported.");
}
}
return iProject;
}
private IContainer collectInput(TreeSelection selection, List<File> inputModels, Shell shell) {
TreePath[] paths = selection.getPaths();
IContainer selectedContainer = null;
HashSet<File> inputFiles = new HashSet<>();
HashSet<File> parents = new HashSet<>();
for (TreePath treePath : paths) {
final Object lastSegment = treePath.getLastSegment();
if (lastSegment instanceof IAdaptable) {
IFile iFile = ((IAdaptable) lastSegment).getAdapter(IFile.class);
if (iFile != null) {
String path = iFile.getRawLocation().toOSString();
File file = new File(path);
try {
inputFiles.add(file.getCanonicalFile());
parents.add(file.getParentFile());
}
catch (IOException e) {
MessageDialog.openError(shell, MODEL_MIGRATION,
"Error fetching the file '" + iFile + "': " + e.getLocalizedMessage());
}
} else {
IContainer container = ((IAdaptable) lastSegment).getAdapter(IContainer.class);
if (container != null) {
selectedContainer = container;
Path modelFilePath = Paths.get(container.getLocationURI());
try (Stream<Path> directoryStream = Files.walk(modelFilePath, 1)) {
inputFiles.addAll(directoryStream
.filter(Files::isRegularFile)
.filter(file -> MigrationHelper.isModelFile(file.toString()))
.map(Path::toFile)
.collect(Collectors.toList()));
} catch (IOException e) {
MessageDialog.openError(shell, MODEL_MIGRATION,
"Failed to collect model files in container: " + e.getLocalizedMessage());
}
}
}
}
}
for (File parent : parents) {
// as the model scope is set to Folder, all the amxmi files present in the folder should be considered
File[] allFilesInDirectory = parent.listFiles( (dir, name) -> MigrationHelper.isModelFile(name) );
inputFiles.addAll(Arrays.asList(allFilesInDirectory));
}
inputModels.addAll(inputFiles);
return selectedContainer;
}
private boolean isSimpleMigration(String context) {
return (context != null && context.equals(SIMPLE_MIGRATION));
}
}