Bug 564324 - Add support for migrating zipped amxmi files

Change-Id: Iefb505749efcbf9c868c149a0d07bd5fab23de0b
Signed-off-by: Dirk Fauth <dirk.fauth@de.bosch.com>
diff --git a/features/org.eclipse.app4mc.amalthea.converters/feature.xml b/features/org.eclipse.app4mc.amalthea.converters/feature.xml
index 07793e9..044d54a 100644
--- a/features/org.eclipse.app4mc.amalthea.converters/feature.xml
+++ b/features/org.eclipse.app4mc.amalthea.converters/feature.xml
@@ -21,14 +21,12 @@
 

    <requires>

       <import plugin="org.eclipse.core.runtime"/>

-      <import plugin="org.eclipse.ui"/>

       <import plugin="org.eclipse.core.resources"/>

       <import plugin="org.eclipse.core.databinding"/>

       <import plugin="org.eclipse.core.databinding.beans"/>

       <import plugin="org.eclipse.core.databinding.property"/>

       <import plugin="org.eclipse.jface.databinding"/>

       <import plugin="org.eclipse.help"/>

-      <import plugin="com.ibm.icu"/>

       <import plugin="org.eclipse.core.expressions"/>

       <import plugin="org.slf4j.api"/>

    </requires>

diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationHelper.java b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationHelper.java
index 55922fd..e6c4b95 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationHelper.java
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationHelper.java
@@ -17,14 +17,20 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
 
 import javax.xml.XMLConstants;
 import javax.xml.stream.XMLEventReader;
@@ -42,6 +48,8 @@
 
 public final class MigrationHelper {
 
+	private static final String UNZIPPED_PREFIX = "unzipped_";
+
 	private static final Logger LOGGER = LoggerFactory.getLogger(MigrationHelper.class);
 
 	public static final String LINE_SEPARATOR = System.getProperty("line.separator");
@@ -50,11 +58,11 @@
 		// empty default constructor
 	}
 
-	public static Map<File, MigrationInputFile> populateModels(
+	public static List<MigrationInputFile> populateModels(
 			List<File> inputModelFiles,
 			MigrationSettings migrationSettings) throws Exception {
 
-		HashMap<File, MigrationInputFile> modelFilesMap = new HashMap<>();
+		ArrayList<MigrationInputFile> modelFiles = new ArrayList<>();
 
 		for (File inputFile : inputModelFiles) {
 
@@ -65,12 +73,12 @@
 			migModelFile.setSelectedFile(inputModelFiles.contains(inputFile));
 
 			// set the model file version
-			migModelFile.setModelVersion(getModelVersion(inputFile));
+			migModelFile.setModelVersion(getModelVersion(migModelFile.getFile()));
 
-			modelFilesMap.put(inputFile, migModelFile);
+			modelFiles.add(migModelFile);
 		}
 
-		return modelFilesMap;
+		return modelFiles;
 	}
 
 	/**
@@ -81,7 +89,7 @@
 	 * @throws IOException If an error occurred on saving the output file.
 	 */
 	public static void saveFiles(MigrationSettings settings) throws IOException {
-		Set<File> keySet = settings.getMigModelFilesMap().keySet();
+		List<MigrationInputFile> migModelFiles = settings.getMigModelFiles();
 
 		boolean updateFileNames = false;
 		if (settings.getInputModelVersion().equals("itea.103")
@@ -96,11 +104,16 @@
 			}
 		}
 
-		for (File inputFile : keySet) {
+		for (MigrationInputFile inputFile : migModelFiles) {
 
+			// skip inputs that have no Document set
+			if (inputFile.getDocument() == null) {
+				continue;
+			}
+			
 			String outputDirectoryLocation = settings.getOutputDirectoryLocation();
 
-			String convertedFileName = inputFile.getName();
+			String convertedFileName = inputFile.getFile().getName();
 
 			if (updateFileNames) {
 				// add amxmi extension to file names which do not have it (and are migrated to versions 1.1.1 or higher)
@@ -112,21 +125,39 @@
 			}
 
 			File outputFile = null;
-
+			Path location = null;
 			if (outputDirectoryLocation != null && !outputDirectoryLocation.equals("")) {
-				String location = outputDirectoryLocation + File.separator + convertedFileName;
-				HelperUtil.saveFile(settings.getMigModelFilesMap().get(inputFile), location, true, true);
-
-				outputFile = new File(location);
+				location = Paths.get(outputDirectoryLocation);
 			}
 			else {
-				String location = inputFile.getParentFile().getAbsolutePath() + File.separator + convertedFileName;
-				HelperUtil.saveFile(settings.getMigModelFilesMap().get(inputFile), location, true, true);
-
-				outputFile = new File(location);
+				location = Paths.get(inputFile.getFile().getParentFile().getAbsolutePath());
 			}
 
+			Path outputFilePath = Paths.get(location.toString(), convertedFileName);
+			HelperUtil.saveFile(inputFile.getDocument(), outputFilePath.toString(), true, true);
+			outputFile = outputFilePath.toFile();
+
 			LOGGER.info("Migrated model file saved @ : {}", outputFile.getAbsolutePath());
+			
+			// now that the migrated files are saved we need to check if the input was zipped
+			if (inputFile.isZipFile()) {
+				Path zipOutputPath = Paths.get(location.toString(), inputFile.getOriginalFile().getName());
+				try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipOutputPath));
+						InputStream fis = Files.newInputStream(outputFilePath)) {
+					ZipEntry zipEntry = new ZipEntry(inputFile.getOriginalFile().getName());
+					zipOut.putNextEntry(zipEntry);
+					byte[] bytes = new byte[1024];
+					int length;
+					while((length = fis.read(bytes)) >= 0) {
+						zipOut.write(bytes, 0, length);
+					}
+				}
+
+				LOGGER.info("Created archive model file @ : {}", zipOutputPath);
+				
+				// delete the migrated unzipped file
+				Files.delete(outputFilePath);
+			}
 		}
 	}
 
@@ -349,8 +380,8 @@
 		// Rename or copy the original file to filename_currentversion.amxmi
 		String newFileName = MigrationHelper.getBackupFileName(migrationInputFile);
 		try {
-			String filebackupName = migrationInputFile.getFile().getParent() + File.separator + newFileName;
-			Files.copy(migrationInputFile.getFile().toPath(), new File(filebackupName).toPath(), StandardCopyOption.REPLACE_EXISTING);
+			String filebackupName = migrationInputFile.getOriginalFile().getParent() + File.separator + newFileName;
+			Files.copy(migrationInputFile.getOriginalFile().toPath(), new File(filebackupName).toPath(), StandardCopyOption.REPLACE_EXISTING);
 			LOGGER.info( "Original model file saved as {}", filebackupName);
 			if (new File(filebackupName).exists()) {
 				return true;
@@ -380,7 +411,7 @@
 	 * @return filename of the input file backup.
 	 */
 	public static String getBackupFileName(MigrationInputFile migrationInputFile) {
-		String fileName = migrationInputFile.getFile().getName();
+		String fileName = migrationInputFile.getOriginalFile().getName();
 		String newFileName = fileName.substring(0, fileName.lastIndexOf("."));
 		String suffixString = "_" + migrationInputFile.getModelVersion();
 		String fileExtension = ".amxmi";
@@ -388,7 +419,7 @@
 		newFileName = newFileName + suffixString + fileExtension;
 		// check if file with newly constructed name already exists then append model
 		// version at end of name
-		if (new File(migrationInputFile.getFile().getParent() + File.separator + newFileName).exists()) {
+		if (new File(migrationInputFile.getOriginalFile().getParent() + File.separator + newFileName).exists()) {
 			newFileName = newFileName.replace(suffixString + fileExtension, suffixString + suffixString + fileExtension);
 		}
 
@@ -440,4 +471,53 @@
 		
 		return result;
 	}
+
+	/**
+	 * Check if the given file is a zip archive.
+	 * 
+	 * @param file The {@link File} to check.
+	 * @return <code>true</code> if the given file is a zip archive,
+	 *         <code>false</code> if not.
+	 */
+	public static boolean isZipFile(File file) {
+		boolean result = false;
+
+		if (file != null) {
+			try (ZipFile f = new ZipFile(file)) {
+				// zipped file detected
+				result = true;
+			} catch (IOException e) {
+				// IOException includes ZipException -> not a zip file
+			}
+		}
+
+		return result;
+	}
+	
+	/**
+	 * Extracts the given input file. Needed in case the .amxmi file is a zip
+	 * archive that contains the model real model file.
+	 * 
+	 * @param input The input file to extract.
+	 * @return The File reference to the unzipped file.
+	 * @throws IOException if an error occurs on the unzip operation.
+	 */
+	public static File temporaryUnzip(File input) throws IOException {
+		Path inputPath = Paths.get(input.toURI());
+		byte[] buffer = new byte[1024];
+        try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(inputPath))) {
+        	ZipEntry zipEntry = zis.getNextEntry();
+        	
+        	Path unzipped = Paths.get(inputPath.getParent().toString(), UNZIPPED_PREFIX + zipEntry.getName());
+    		try (OutputStream fos = Files.newOutputStream(unzipped)) {
+    			int len;
+    			while ((len = zis.read(buffer)) > 0) {
+    				fos.write(buffer, 0, len);
+    			}
+    		}
+    		zis.closeEntry();
+    		
+    		return unzipped.toFile();
+        }
+	}
 }
diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationInputFile.java b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationInputFile.java
index e074fc4..46d7492 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationInputFile.java
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationInputFile.java
@@ -16,6 +16,9 @@
 package org.eclipse.app4mc.amalthea.converters.common;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 
 import org.eclipse.app4mc.amalthea.converters.common.utils.HelperUtil;
 import org.jdom2.Document;
@@ -28,13 +31,17 @@
 	
 	private String modelVersion = "";
 
-	private boolean isSelectedFile;
+	private boolean selectedFile;
 
 	private File file;
+	
+	private File originalFile;
 
 	private String projectRelativePath;
 
 	private Document document;
+	
+	private boolean zipFile;
 
 	/*- this field is used to mark ModelFiles, if they have different versions than other files */
 	private boolean isVersionDifferent;
@@ -48,19 +55,26 @@
 	}
 
 	public boolean isSelectedFile() {
-		return this.isSelectedFile;
+		return this.selectedFile;
 	}
 
 	public void setSelectedFile(boolean isSelectedFile) {
-		this.isSelectedFile = isSelectedFile;
+		this.selectedFile = isSelectedFile;
 	}
 
 	public File getFile() {
 		return this.file;
 	}
 
-	public void setFile(File file, File project) {
-		this.file = file;
+	public void setFile(File file, File project) throws IOException {
+		if (MigrationHelper.isZipFile(file)) {
+			this.zipFile = true;
+			this.file = MigrationHelper.temporaryUnzip(file);
+		} else {
+			this.zipFile = false;
+			this.file = file;
+		}
+		this.originalFile = file;
 		this.projectRelativePath = project.toURI().relativize(file.toURI()).getPath();
 	}
 
@@ -90,4 +104,22 @@
 	public void setVersionDifferent(boolean isVersionDifferent) {
 		this.isVersionDifferent = isVersionDifferent;
 	}
+
+	public boolean isZipFile() {
+		return zipFile;
+	}
+
+	public File getOriginalFile() {
+		return originalFile;
+	}
+	
+	public void dispose() {
+		if (this.zipFile && this.file.exists()) {
+			try {
+				Files.delete(Paths.get(this.file.getAbsolutePath()));
+			} catch (IOException e) {
+				LOGGER.error("Failed to delete temporary unzipped file {}", this.file.getAbsolutePath(), e);
+			}
+		}
+	}
 }
diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationProcessor.java b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationProcessor.java
index 3d4761b..d6e6bbd 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationProcessor.java
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationProcessor.java
@@ -186,6 +186,8 @@
 					MigrationHelper.saveFiles(settings);
 				} catch (IOException e) {
 					throw new MigrationException("Error on saving migrated files.", e);
+				} finally {
+					settings.close();
 				}
 			}
 
diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationSettings.java b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationSettings.java
index d72474e..5e370f8 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationSettings.java
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.common/src/org/eclipse/app4mc/amalthea/converters/common/MigrationSettings.java
@@ -24,9 +24,9 @@
 import org.eclipse.app4mc.amalthea.converters.common.utils.ModelVersion;
 import org.jdom2.Document;
 
-public class MigrationSettings {
+public class MigrationSettings implements AutoCloseable {
 
-	private List<MigrationInputFile> migModelFiles = new ArrayList<MigrationInputFile>();
+	private List<MigrationInputFile> migModelFiles = new ArrayList<>();
 
 	private String inputModelVersion;
 
@@ -81,7 +81,7 @@
 
 	public Map<File, Document> getMigModelFilesMap() {
 
-		final Map<File, Document> migModelsMap = new HashMap<>();
+		final HashMap<File, Document> migModelsMap = new HashMap<>();
 
 		for (final MigrationInputFile migModelFile : this.migModelFiles) {
 			Document document = migModelFile.getDocument();
@@ -93,4 +93,8 @@
 		return migModelsMap;
 	}
 
+	@Override
+	public void close() {
+		this.migModelFiles.forEach(MigrationInputFile::dispose);
+	}
 }
diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.headless.app/src/org/eclipse/app4mc/amalthea/converters/headless/app/ModelMigrationCommand.java b/plugins/org.eclipse.app4mc.amalthea.converters.headless.app/src/org/eclipse/app4mc/amalthea/converters/headless/app/ModelMigrationCommand.java
index 238cbc3..37fd297 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.headless.app/src/org/eclipse/app4mc/amalthea/converters/headless/app/ModelMigrationCommand.java
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.headless.app/src/org/eclipse/app4mc/amalthea/converters/headless/app/ModelMigrationCommand.java
@@ -95,11 +95,12 @@
 
 			// build up MigrationSettings
 			// same as AmaltheaModelMigrationHandler#collectInput
-			MigrationSettings migrationSettings = new MigrationSettings();
-			migrationSettings.setProject(modelFilePath.getParent().toFile());
-			migrationSettings.setMigrationModelVersion(outputModelVersion);
-
-			convert(Arrays.asList(modelFilePath.toFile()), migrationSettings, noBackup);
+			try (MigrationSettings migrationSettings = new MigrationSettings()) {
+				migrationSettings.setProject(modelFilePath.getParent().toFile());
+				migrationSettings.setMigrationModelVersion(outputModelVersion);
+				
+				convert(Arrays.asList(modelFilePath.toFile()), migrationSettings, noBackup);
+			}
 		} else {
 			System.err.println("Given parameter \"" + filename + "\" is neither a directory nor a model file!");
 		}
@@ -114,11 +115,12 @@
 					.collect(Collectors.toList());
 			
 			if (!modelFiles.isEmpty()) {
-				MigrationSettings migrationSettings = new MigrationSettings();
-				migrationSettings.setProject(modelFilePath.toFile());
-				migrationSettings.setMigrationModelVersion(outputModelVersion);
-
-				convert(modelFiles, migrationSettings, noBackup);
+				try (MigrationSettings migrationSettings = new MigrationSettings()) {
+					migrationSettings.setProject(modelFilePath.toFile());
+					migrationSettings.setMigrationModelVersion(outputModelVersion);
+					
+					convert(modelFiles, migrationSettings, noBackup);
+				}
 			}
 		} catch (IOException e) {
 			System.err.println("Failed to load model files");
@@ -155,9 +157,8 @@
 
 		// same as ModelLoaderJob
 		try {
-			Map<File, MigrationInputFile> modelFilesMap =
-					MigrationHelper.populateModels(inputFiles, migrationSettings);
-			migrationSettings.getMigModelFiles().addAll(modelFilesMap.values());
+			List<MigrationInputFile> modelFiles = MigrationHelper.populateModels(inputFiles, migrationSettings);
+			migrationSettings.getMigModelFiles().addAll(modelFiles);
 		} catch (Exception e) {
 			System.err.println("Failed to load model files");
 			e.printStackTrace();
diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.app4mc.amalthea.converters.ui/META-INF/MANIFEST.MF
index aef6dee..ea82e49 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.ui/META-INF/MANIFEST.MF
@@ -11,7 +11,6 @@
  org.eclipse.core.databinding.beans,
  org.eclipse.core.databinding.property,
  org.eclipse.jface.databinding,
- org.eclipse.e4.ui.model.workbench;bundle-version="2.1.0.v20180429-1333",
  org.eclipse.core.expressions;bundle-version="3.6.100",
  org.eclipse.e4.core.services,
  org.eclipse.jface;bundle-version="3.14.0",
diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/handlers/AmaltheaModelMigrationHandler.java b/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/handlers/AmaltheaModelMigrationHandler.java
index 253d1f7..ea84c4c 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/handlers/AmaltheaModelMigrationHandler.java
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/handlers/AmaltheaModelMigrationHandler.java
@@ -51,6 +51,7 @@
 import org.eclipse.jface.viewers.ISelection;

 import org.eclipse.jface.viewers.TreePath;

 import org.eclipse.jface.viewers.TreeSelection;

+import org.eclipse.jface.window.Window;

 import org.eclipse.swt.widgets.Display;

 import org.eclipse.swt.widgets.Shell;

 import org.slf4j.Logger;

@@ -113,7 +114,7 @@
 

 							@Override

 							public void run() {

-

+								boolean execute = false;

 								try {

 									boolean inputValid = MigrationHelper.isInputModelVersionValid(migrationSettings);

 

@@ -177,13 +178,17 @@
 											} else {

 												// open dialog so the user can configure the settings

 												ModelMigrationDialog dialog = new ModelMigrationDialog(shell, migrationProcessor, migrationSettings, iProject);

-												dialog.open();

+												execute = dialog.open() == Window.OK;

 											}

 										}

 									}

 								} catch (MigrationException e) {

 									MessageDialog.openError(shell, "AMALTHEA Model Migration",

 											e.getLocalizedMessage());

+								} finally {

+									if (!execute) {

+										migrationSettings.close();

+									}

 								}

 

 							}

@@ -196,6 +201,8 @@
 

 							@Override

 							public void run() {

+								migrationSettings.close();

+								

 								MessageDialog.openError(shell, "AMALTHEA Model Migration",

 										jobEvent.getResult().getMessage());

 							}

diff --git a/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/jobs/ModelLoaderJob.java b/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/jobs/ModelLoaderJob.java
index 76a1112..345f8cb 100644
--- a/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/jobs/ModelLoaderJob.java
+++ b/plugins/org.eclipse.app4mc.amalthea.converters.ui/src/org/eclipse/app4mc/amalthea/converters/ui/jobs/ModelLoaderJob.java
@@ -17,7 +17,6 @@
 

 import java.io.File;

 import java.util.List;

-import java.util.Map;

 

 import org.eclipse.app4mc.amalthea.converters.common.MigrationHelper;

 import org.eclipse.app4mc.amalthea.converters.common.MigrationInputFile;

@@ -52,9 +51,8 @@
 		subMonitor.setTaskName("Loading selected model files ...");

 

 		try {

-			Map<File, MigrationInputFile> modelFilesMap =

-					MigrationHelper.populateModels(this.inputModels, this.migrationSettings);

-			this.migrationSettings.getMigModelFiles().addAll(modelFilesMap.values());

+			List<MigrationInputFile> modelFiles = MigrationHelper.populateModels(this.inputModels, this.migrationSettings);

+			this.migrationSettings.getMigModelFiles().addAll(modelFiles);

 		}

 		catch (final Exception e1) {

 			Bundle bundle = FrameworkUtil.getBundle(getClass());

diff --git a/pom.xml b/pom.xml
index a56a40f..13438a5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,10 @@
 		<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../../releng/org.eclipse.app4mc.converters.p2repo/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
 		<sonar.surefire.reportsPath>../../tests/${project.artifactId}.tests/target/surefire-reports/</sonar.surefire.reportsPath>
 		<sonar.java.source>8</sonar.java.source>
+		<!-- coverage exclusions -->
+		<sonar.coverage.exclusions>**/*.tests/**/*.java</sonar.coverage.exclusions>
+		<!-- duplication exclusion -->
+		<sonar.cpd.exclusions>**/*.tests/**/*.java</sonar.cpd.exclusions>
 	</properties>
 
 	<pluginRepositories>
diff --git a/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.target b/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.target
index dbd6984..dc1ef53 100644
--- a/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.target
+++ b/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.target
@@ -1,12 +1,11 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="Amalthea Model Migration Target" sequenceNumber="1582013112">
+<target name="Amalthea Model Migration Target" sequenceNumber="1592297242">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="true" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
       <unit id="org.eclipse.sdk.ide" version="4.14.0.I20191210-0610"/>
       <unit id="org.eclipse.equinox.sdk.feature.group" version="3.20.0.v20191122-2104"/>
-      <unit id="org.eclipse.emf.sdk.feature.group" version="2.20.0.v20191028-0905"/>
       <unit id="javax.xml" version="1.3.4.v201005080400"/>
       <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
diff --git a/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.tpd b/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.tpd
index 99af213..712ab8e 100644
--- a/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.tpd
+++ b/releng/org.eclipse.app4mc.converters.target/org.eclipse.app4mc.converters.target.tpd
@@ -5,7 +5,6 @@
 location "http://download.eclipse.org/releases/2019-12" {
 	org.eclipse.sdk.ide
 	org.eclipse.equinox.sdk.feature.group
-	org.eclipse.emf.sdk.feature.group
 	javax.xml
 	org.slf4j.api [1.7.2,1.7.3)
 	org.slf4j.impl.log4j12 [1.7.2,2.0.0)
diff --git a/tests/org.eclipse.app4mc.amalthea.converters.common.tests/TestModels/input/namespace/model.amxmi b/tests/org.eclipse.app4mc.amalthea.converters.common.tests/TestModels/input/namespace/model.amxmi
new file mode 100644
index 0000000..6bca76f
--- /dev/null
+++ b/tests/org.eclipse.app4mc.amalthea.converters.common.tests/TestModels/input/namespace/model.amxmi
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<am:Amalthea xmlns:am="http://app4mc.eclipse.org/amalthea/0.9.6" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmi:version="2.0">
+  <hwModel />
+</am:Amalthea>
diff --git a/tests/org.eclipse.app4mc.amalthea.converters.common.tests/TestModels/input/zipped/model.amxmi b/tests/org.eclipse.app4mc.amalthea.converters.common.tests/TestModels/input/zipped/model.amxmi
new file mode 100644
index 0000000..6a80376
--- /dev/null
+++ b/tests/org.eclipse.app4mc.amalthea.converters.common.tests/TestModels/input/zipped/model.amxmi
Binary files differ
diff --git a/tests/org.eclipse.app4mc.amalthea.converters.common.tests/src/org/eclipse/app4mc/amalthea/converters/common/tests/NamespaceConverterZippedTest.java b/tests/org.eclipse.app4mc.amalthea.converters.common.tests/src/org/eclipse/app4mc/amalthea/converters/common/tests/NamespaceConverterZippedTest.java
new file mode 100644
index 0000000..0eea459
--- /dev/null
+++ b/tests/org.eclipse.app4mc.amalthea.converters.common.tests/src/org/eclipse/app4mc/amalthea/converters/common/tests/NamespaceConverterZippedTest.java
@@ -0,0 +1,116 @@
+/*********************************************************************************
+ * Copyright (c) 2020 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.common.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.app4mc.amalthea.converters.common.MigrationHelper;
+import org.eclipse.app4mc.amalthea.converters.common.MigrationInputFile;
+import org.eclipse.app4mc.amalthea.converters.common.MigrationSettings;
+import org.eclipse.app4mc.amalthea.converters.common.utils.ModelVersion;
+import org.junit.Test;
+
+public class NamespaceConverterZippedTest {
+
+	public static final String GLOBAL_TEST_INPUT_DIRECTORY = "./TestModels/input";
+
+	public static final Path ZIP_FILE = Paths.get(GLOBAL_TEST_INPUT_DIRECTORY + File.separator + "/zipped/model.amxmi").toAbsolutePath();
+
+	@Test
+	public void shouldCheckZipFile() {
+		final String nonZipFilePath = GLOBAL_TEST_INPUT_DIRECTORY + File.separator + "/namespace/model.amxmi";
+
+		assertTrue(MigrationHelper.isZipFile(ZIP_FILE.toFile()));
+		assertFalse(MigrationHelper.isZipFile(new File(nonZipFilePath)));
+		assertFalse(MigrationHelper.isZipFile(null));
+	}
+	
+	@Test
+	public void shouldTemporaryUnzipFile() throws IOException {
+		MigrationInputFile migModelFile = new MigrationInputFile();
+		migModelFile.setFile(ZIP_FILE.toFile().getCanonicalFile(), ZIP_FILE.getParent().toFile());
+	
+		// as the input is a zip file we expect the temporary unzipped file
+		File unzipped = migModelFile.getFile(); 
+		assertNotNull(unzipped);
+		assertTrue(unzipped.exists());
+		assertEquals("unzipped_model.amxmi", unzipped.getName());
+		
+		unzipped.deleteOnExit();
+	}
+	
+	@Test
+	public void shouldPopulateModel() throws Exception {
+		MigrationInputFile input = null;
+		try (MigrationSettings migrationSettings = new MigrationSettings()) {
+			migrationSettings.setProject(ZIP_FILE.getParent().toFile());
+			migrationSettings.setMigrationModelVersion(ModelVersion._097.getVersion());
+			
+			List<MigrationInputFile> inputFiles = MigrationHelper.populateModels(Arrays.asList(ZIP_FILE.toFile()), migrationSettings);
+			migrationSettings.getMigModelFiles().addAll(inputFiles);
+			
+			assertEquals(1, inputFiles.size());
+			
+			input = inputFiles.get(0);
+			assertTrue(input.isZipFile());
+			assertEquals(ModelVersion._096.getVersion(), input.getModelVersion());
+			assertEquals("model.amxmi", input.getOriginalFile().getName());
+			assertEquals("unzipped_model.amxmi", input.getFile().getName());
+			
+			// test that disposing really deletes the temporary created files
+			assertTrue(input.getFile().exists());
+		}
+
+		assertFalse(input.getFile().exists());
+	}
+	
+	@Test
+	public void shouldCreateBackupOfZip() throws Exception {
+		MigrationSettings migrationSettings = new MigrationSettings();
+		migrationSettings.setProject(ZIP_FILE.getParent().toFile());
+		migrationSettings.setMigrationModelVersion(ModelVersion._097.getVersion());
+
+		List<MigrationInputFile> inputFiles = MigrationHelper.populateModels(Arrays.asList(ZIP_FILE.toFile()), migrationSettings);
+		
+		assertEquals(1, inputFiles.size());
+		
+		MigrationInputFile input = inputFiles.get(0);
+
+		String backupFileName = MigrationHelper.getBackupFileName(input);
+		
+		assertEquals("model_0.9.6.amxmi", backupFileName);
+		
+		assertTrue(MigrationHelper.createBackupFile(input));
+		
+		Path backupPath = Paths.get(ZIP_FILE.getParent().toString(), backupFileName);
+		File backupFile = backupPath.toFile();
+		assertTrue(backupFile.exists());
+		assertTrue(MigrationHelper.isZipFile(backupFile));
+		
+		backupFile.deleteOnExit();
+		input.getFile().deleteOnExit();
+	}
+
+}