blob: 9d9ee14774f23869dce7e0096cdd1308948f493a [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2019, 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.common;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import org.eclipse.app4mc.amalthea.converters.common.base.ICache;
import org.eclipse.app4mc.amalthea.converters.common.base.IConverter;
import org.eclipse.app4mc.amalthea.converters.common.base.IPostProcessor;
import org.eclipse.app4mc.util.sessionlog.SessionLogger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.jdom2.Document;
import org.osgi.service.component.ComponentFactory;
import org.osgi.service.component.ComponentInstance;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
@Component(service = MigrationProcessor.class)
public class MigrationProcessor {
private static final String NEWLINE = System.getProperty("line.separator");
@Reference(target = "(component.factory=" + ServiceConstants.MODEL_MIGRATION_FACTORY + ")")
ComponentFactory<ModelMigration> factory;
@Reference(target = "(component.factory=" + "org.eclipse.app4mc.amalthea.sessionlog.factory" + ")")
ComponentFactory<SessionLogger> loggerFactory;
/**
* Execute the migration for the provided {@link MigrationSettings}.
*
* @param settings The {@link MigrationSettings} containing the settings for the
* migration.
* @param monitor The progress monitor to give feedback to the caller. Can be
* <code>null</code>.
* @return A {@link MigrationStatusCode} indicating the status of the migration.
* @throws MigrationException In case saving the migrated files fails.
*/
public int execute(MigrationSettings settings, IProgressMonitor monitor) {
ComponentInstance<SessionLogger> loggerInstance = loggerFactory.newInstance(null);
SessionLogger logger = loggerInstance.getInstance();
settings.getMigModelFiles().forEach(f -> f.setSessionLogger(logger));
try {
if (monitor != null) {
monitor.setTaskName("Collecting information for intermediate migration steps");
}
// check if a migration needs to be executed
Map<String, String> migStepEntries = MigrationHelper.generateMigrationSteps(
settings.getInputModelVersion(),
settings.getMigrationModelVersion());
if (migStepEntries.size() == 0) {
logger.error("Migration not supported for the selected model versions. \nInput Model version : \"{0}\" Output Model Version : \"{1}\"",
settings.getInputModelVersion(),
settings.getMigrationModelVersion());
return MigrationStatusCode.UNSUPPORTED_MODEL_VERSIONS;
}
SubMonitor subMonitor = monitor != null ? SubMonitor.convert(monitor, migStepEntries.size() + 1) : null;
Map<File, Document> fileDocumentMapping = settings.getMigModelFilesMap();
// info log
StringBuilder builder = new StringBuilder();
builder.append(NEWLINE);
builder.append("*******************************************************************************************************************");
builder.append(NEWLINE);
builder.append("\t\t Starting model migration for the following AMALTHEA models: ");
builder.append(NEWLINE);
for (final File modelFile : fileDocumentMapping.keySet()) {
builder.append("\t\t -- ");
builder.append(modelFile.getAbsolutePath());
builder.append(NEWLINE);
}
builder.append(NEWLINE);
builder.append("*******************************************************************************************************************");
builder.append(NEWLINE);
logger.info("{0}", builder);
boolean conversionPerformed = false;
String currentModelVersion = settings.getInputModelVersion();
while (!currentModelVersion.equals(settings.getMigrationModelVersion())) {
if (subMonitor != null && subMonitor.isCanceled()) {
return MigrationStatusCode.CANCEL;
}
// define the target filters and create the ModelMigration component instance
Dictionary<String, Object> properties = new Hashtable<>();
String inputFilterExp = "(input_model_version=" + currentModelVersion + ")";
String inputOuputFilterExpression = "(&(input_model_version=" + currentModelVersion + ")(output_model_version=" + migStepEntries.get(currentModelVersion) + "))";
properties.put(ServiceConstants.INPUT_MODEL_VERSION_PROPERTY, currentModelVersion);
properties.put(ServiceConstants.OUTPUT_MODEL_VERSION_PROPERTY, migStepEntries.get(currentModelVersion));
properties.put("caches.target", inputFilterExp);
properties.put("converter.target", inputOuputFilterExpression);
properties.put("postProcessor.target", inputOuputFilterExpression);
ComponentInstance<ModelMigration> newInstance = factory.newInstance(properties);
ModelMigration modelMigration = newInstance.getInstance();
String outputModelVersion = modelMigration.getOutputModelVersion();
// execute migration
if (subMonitor != null) {
subMonitor.setTaskName("Migrating AMALTHEA models from : " + currentModelVersion + " to " + outputModelVersion);
}
logger.info("=========== START: Migrating AMALTHEA models from : {0} to {1} ========== ", currentModelVersion, outputModelVersion);
// build caches
// build up the cache for the current file set
for (ICache cache : modelMigration.getCaches()) {
// clear the cache to avoid any side effects if a previous migration failed with an exception
cache.clearCacheMap();
cache.buildCache(fileDocumentMapping);
}
// execute conversion
for (IConverter converter : modelMigration.getConverter()) {
for (File file : fileDocumentMapping.keySet()) {
converter.convert(file, fileDocumentMapping, modelMigration.getCaches());
conversionPerformed = true;
}
}
for (IPostProcessor postProcessor : modelMigration.getPostProcessor()) {
postProcessor.process(fileDocumentMapping);
}
logger.info("=========== END: Migrating AMALTHEA models from : {0} to {1} =========== \n\r", currentModelVersion, outputModelVersion);
if (currentModelVersion.equals(outputModelVersion)) {
// if the output is already the current model version,
// we need to update the output model version to ensure
// that we exit the loop
outputModelVersion = migStepEntries.get(currentModelVersion);
}
currentModelVersion = outputModelVersion;
// clear the cache to ensure there are not leftovers on the next migration
for (ICache cache : modelMigration.getCaches()) {
cache.clearCacheMap();
}
if (subMonitor != null) {
subMonitor.worked(1);
}
// destroy the created component instance
newInstance.dispose();
}
if (conversionPerformed) {
if (subMonitor != null) {
subMonitor.setTaskName("Saving migrated AMALTHEA model files ");
}
try {
MigrationHelper.saveFiles(settings, logger);
} catch (IOException e) {
throw new MigrationException("Error on saving migrated files.", e);
} finally {
settings.close();
}
}
if (subMonitor != null) {
subMonitor.worked(1);
}
return MigrationStatusCode.OK;
} finally {
logger.info("Migration session finished");
String dateToStr = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss").format(new Date());
logger.flush(new File(settings.getOutputDirectoryLocation(), "ModelMigration__" + dateToStr + ".log"));
loggerInstance.dispose();
}
}
}