/** | |
******************************************************************************** | |
* 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)); | |
} | |
} |