blob: e8c16cba55e1f5384f210b60d77d804b6f14ed0d [file] [log] [blame]
/*******************************************************************************
*
* Copyright (c) 2018, 2020 Robert Bosch GmbH.
*
* 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.transformation.registry;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import org.eclipse.app4mc.transformation.ServiceConstants;
import org.eclipse.app4mc.transformation.executiontype.IModelToModelConfig;
import org.eclipse.app4mc.transformation.executiontype.IModelToTextConfig;
import org.eclipse.app4mc.transformation.transformers.Model2ModelRootTransformer;
import org.eclipse.app4mc.transformation.transformers.Model2TextRootTransformer;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(
configurationPid = ServiceConstants.SESSION_CONFIGURATION_PID,
configurationPolicy = ConfigurationPolicy.REQUIRE)
public class TransformerRegistry {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String TRANSFORMATION = "transformation";
private static final Logger LOG = LoggerFactory.getLogger(TransformerRegistry.class);
private String logFilePath;
private AtomicBoolean transformationStarted = new AtomicBoolean(false);
ScheduledExecutorService scheduledExecutorService;
ScheduledFuture<?> killCheck;
@Reference
ConfigurationAdmin configAdmin;
String sessionName;
private String[] m2mKeys;
private String[] m2tKeys;
private HashMap<String, Model2ModelRootTransformer> m2mTransformers = new HashMap<>();
private HashMap<String, IModelToModelConfig> m2mConfigs = new HashMap<>();
private HashMap<String, Model2TextRootTransformer> m2tTransformers = new HashMap<>();
private HashMap<String, IModelToTextConfig> m2tConfigs = new HashMap<>();
@Activate
void activate(Map<String, ?> properties) {
this.logFilePath = (String) properties.get("log_file");
this.sessionName = (String) properties.get(ServiceConstants.SESSION_ID);
String m2mTransformersKey = (String) properties.get("m2mTransformers");
this.m2mKeys = m2mTransformersKey != null ? m2mTransformersKey.split(",") : new String[0];
LOG.debug("m2m transformer to execute: {}", (Object[]) this.m2mKeys);
String m2tTransformersKey = (String) properties.get("m2tTransformers");
this.m2tKeys = m2tTransformersKey != null ? m2tTransformersKey.split(",") : new String[0];
LOG.debug("m2t transformer to execute: {}", (Object[]) this.m2tKeys);
this.scheduledExecutorService = Executors.newScheduledThreadPool(1);
this.killCheck = this.scheduledExecutorService.schedule(
() -> {
// if after 10 seconds we check if all required transformers are available
// if not we log an error and kill the session
for (String key : this.m2mKeys) {
if (!this.m2mTransformers.containsKey(key)) {
LOG.error("M2M transformer for key '{}' is not available in the runtime", key);
}
}
for (String key : this.m2mKeys) {
if (!this.m2mConfigs.containsKey(key)) {
LOG.error("M2M configuration for key '{}' is not available in the runtime", key);
}
}
for (String key : this.m2tKeys) {
if (!this.m2tTransformers.containsKey(key)) {
LOG.error("M2T transformer for key '{}' is not available in the runtime", key);
}
}
// check that for all configured keys there is a configuration available
for (String key : this.m2tKeys) {
if (!this.m2tConfigs.containsKey(key)) {
LOG.error("M2T configuration for key '{}' is not available in the runtime", key);
}
}
LOG.error("Transformation configuration invalid! Stopping the process!");
try {
Configuration configuration =
this.configAdmin.getFactoryConfiguration(ServiceConstants.SESSION_CONFIGURATION_PID, this.sessionName, "?");
configuration.delete();
} catch (IOException e) {
LOG.error("Failed to delete the session configuration", e);
}
},
10, TimeUnit.SECONDS);
// if the transformers were already set prior to the activation, we need to start
checkAllReferencesSet();
}
@Deactivate
void deactivate() {
this.scheduledExecutorService.shutdownNow();
}
// Model 2 Model
@Reference(
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
void setM2mTransformer(Model2ModelRootTransformer transformer, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
this.m2mTransformers.put(transformationKey, transformer);
LOG.debug("m2m transformer registered for key {}", transformationKey);
checkAllReferencesSet();
}
}
void unsetM2mTransformer(Model2ModelRootTransformer transformer, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
this.m2mTransformers.remove(transformationKey);
}
}
@Reference(
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
void setM2mConfig(IModelToModelConfig config, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
this.m2mConfigs.put(transformationKey, config);
LOG.debug("m2m config registered for key {}", transformationKey);
checkAllReferencesSet();
}
}
void unsetM2mConfig(IModelToModelConfig transformer, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
this.m2mConfigs.remove(transformationKey);
}
}
public List<Model2ModelRootTransformer> getModelToModelTransformer(String... transformation){
List<String> keys = Arrays.asList(transformation);
return this.m2mTransformers.entrySet().stream()
.filter(entry -> keys.contains(entry.getKey()))
.map(Entry<String, Model2ModelRootTransformer>::getValue)
.collect(Collectors.toList());
}
public List<IModelToModelConfig> getModelToModelConfig(String... transformation) {
List<String> keys = Arrays.asList(transformation);
return this.m2mConfigs.entrySet().stream()
.filter(entry -> keys.contains(entry.getKey()))
.map(Entry<String, IModelToModelConfig>::getValue)
.collect(Collectors.toList());
}
// Model 2 Text
@Reference(
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
void setM2tTransformer(Model2TextRootTransformer transformer, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
m2tTransformers.put(transformationKey, transformer);
LOG.debug("m2t transformer registered for key {}", transformationKey);
checkAllReferencesSet();
}
}
void unsetM2tTransformer(Model2TextRootTransformer transformer, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
m2tTransformers.remove(transformationKey);
}
}
@Reference(
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
void setM2tConfig(IModelToTextConfig config, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
m2tConfigs.put(transformationKey, config);
LOG.debug("m2t config registered for key {}", transformationKey);
checkAllReferencesSet();
}
}
void unsetM2tConfig(IModelToTextConfig transformer, Map<String, ?> properties) {
String transformationKey = (String) properties.get(TRANSFORMATION);
if (transformationKey != null) {
m2tConfigs.remove(transformationKey);
}
}
public List<Model2TextRootTransformer> getModelToTextTransformer(String... transformation) {
List<String> keys = Arrays.asList(transformation);
return m2tTransformers.entrySet().stream()
.filter(entry -> keys.contains(entry.getKey()))
.map(Entry<String, Model2TextRootTransformer>::getValue)
.collect(Collectors.toList());
}
public List<IModelToTextConfig> getModelToTextConfig(String... transformation) {
List<String> keys = Arrays.asList(transformation);
return m2tConfigs.entrySet().stream()
.filter(entry -> keys.contains(entry.getKey()))
.map(Entry<String, IModelToTextConfig>::getValue)
.collect(Collectors.toList());
}
private void checkAllReferencesSet() {
if (this.configAdmin == null || this.m2mKeys == null || this.m2tKeys == null) {
// this component is not activated yet, so no action to perform
return;
}
// check that for all configured keys there is a root transformer available
boolean allM2MTransformersSet = true;
for (String key : this.m2mKeys) {
if (!this.m2mTransformers.containsKey(key)) {
allM2MTransformersSet = false;
break;
}
}
// check that for all configured keys there is a configuration available
boolean allM2MConfigsSet = true;
for (String key : this.m2mKeys) {
if (!this.m2mConfigs.containsKey(key)) {
allM2MConfigsSet = false;
break;
}
}
// check that for all configured keys there is a root transformer available
boolean allM2TTransformersSet = true;
for (String key : this.m2tKeys) {
if (!this.m2tTransformers.containsKey(key)) {
allM2TTransformersSet = false;
break;
}
}
// check that for all configured keys there is a configuration available
boolean allM2TConfigsSet = true;
for (String key : this.m2tKeys) {
if (!this.m2tConfigs.containsKey(key)) {
allM2TConfigsSet = false;
break;
}
}
if (allM2MTransformersSet && allM2MConfigsSet
&& allM2TTransformersSet && allM2TConfigsSet
&& this.transformationStarted.compareAndSet(false, true)) {
// only start the transformation once if all required transformations are set
this.killCheck.cancel(true);
startTransformation();
}
}
void startTransformation() {
try {
// activate session file logging
System.setProperty("APP4MC_TRANSFORMATION_LOG_FILE", logFilePath);
LOG.info("Starting Model transformation ...");
// Model to Model transformation
for (String m2mKey : this.m2mKeys) {
LOG.info("****************** Model to Model Transformation : {} *******************************", m2mKey);
List<Model2ModelRootTransformer> m2mTransformers = getModelToModelTransformer(m2mKey);
List<IModelToModelConfig> m2mConfigs = getModelToModelConfig(m2mKey);
if (m2mTransformers.size() > 0 && m2mConfigs.size() > 0) {
for (Model2ModelRootTransformer model2ModelRootTransformer : m2mTransformers) {
LOG.info("** Executing M2M transformer : {}", model2ModelRootTransformer.getClass().getTypeName());
for (IModelToModelConfig m2mConfig : m2mConfigs) {
model2ModelRootTransformer.m2mTransformation(m2mConfig.getInputResourceSet(),
m2mConfig.getOuputResourceSet());
}
}
} else {
LOG.error("Unable to execute the M2M transformation for key : {}", m2mKey);
String info = "Following configuration is loaded for M2M with key : " + m2mKey
+ LINE_SEPARATOR + "Model2ModelRootTransformer objects : "
+ Arrays.toString(m2mTransformers.toArray()) + LINE_SEPARATOR
+ "IModelToModelConfig objects : " + Arrays.toString(m2mConfigs.toArray());
LOG.info(info);
}
}
// Model to Text transformation
for (String m2tKey : this.m2tKeys) {
LOG.info("****************** Model to Text Transformation : {} ****************************", m2tKey);
List<Model2TextRootTransformer> m2tTransformers = getModelToTextTransformer(m2tKey);
List<IModelToTextConfig> m2tConfigs = getModelToTextConfig(m2tKey);
if (m2tTransformers.size() > 0 && m2tConfigs.size() > 0) {
for (Model2TextRootTransformer model2TextRootTransformer : m2tTransformers) {
LOG.info("** Executing M2T transformer : {}", model2TextRootTransformer.getClass().getTypeName());
for (IModelToTextConfig m2tConfig : m2tConfigs) {
model2TextRootTransformer.m2tTransformation(m2tConfig.getInputResourceSet());
}
}
} else {
LOG.error("Unable to execute the M2T transformation for key : {}", m2tKey);
String info = "Following configuration is loaded for M2T with key : " + m2tKey
+ LINE_SEPARATOR + "Model2TextRootTransformer objects : "
+ Arrays.toString(m2tTransformers.toArray()) + LINE_SEPARATOR
+ "IModelToTextConfig objects : " + Arrays.toString(m2tConfigs.toArray());
LOG.info(info);
}
}
LOG.info("Transformation execution session '{}' completed.", this.sessionName);
// once we are done, we delete the configuration to clean up
Configuration configuration =
this.configAdmin.getFactoryConfiguration(ServiceConstants.SESSION_CONFIGURATION_PID, this.sessionName, "?");
configuration.delete();
} catch (IOException e) {
LOG.error("Failed to delete the session configuration", e);
} finally {
// removing the system property will disable the TransformationFileAppender
System.clearProperty("APP4MC_TRANSFORMATION_LOG_FILE");
LOG.info("Transformation session finished");
}
}
}