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