blob: f54ce75cf6695af7440716cce31d8a5dc467f955 [file] [log] [blame]
/*******************************************************************************
*
* Copyright (c) 2018, 2021 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.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.app4mc.transformation.ServiceConstants;
import org.eclipse.app4mc.transformation.TransformationConstants;
import org.eclipse.app4mc.transformation.transformers.Model2ModelRootTransformer;
import org.eclipse.app4mc.transformation.transformers.Model2TextRootTransformer;
import org.eclipse.app4mc.util.sessionlog.SessionLogWriter;
import org.eclipse.app4mc.util.sessionlog.SessionLogger;
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.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.log.Logger;
import org.osgi.service.log.LoggerFactory;
/**
* Configured OSGi service component to consume root transformer and start the
* transformation process once all configured dependencies are resolved.
* <p>
* Can also be used outside an OSGi context. For this case there is API provided
* that allows to register root transformer and configurations and start the
* transformation programmatically.
* </p>
*/
@Component(
configurationPid = ServiceConstants.SESSION_CONFIGURATION_PID,
configurationPolicy = ConfigurationPolicy.REQUIRE,
service=TransformerRegistry.class)
public class TransformerRegistry {
private String logFilePath;
private AtomicBoolean transformationStarted = new AtomicBoolean(false);
LoggerFactory factory;
Logger osgiLogger;
@Reference
EventAdmin eventAdmin;
SessionLogger logger;
String sessionName;
private List<Model2ModelRootTransformer> m2mTransformers = new ArrayList<>();
private List<Model2TextRootTransformer> m2tTransformers = new ArrayList<>();
@Activate
void activate(Map<String, ?> properties) {
this.logFilePath = (String) properties.get(TransformationConstants.LOG_FILE);
this.sessionName = (String) properties.get(ServiceConstants.SESSION_ID);
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
void setLogger(LoggerFactory factory) {
this.factory = factory;
this.osgiLogger = factory.getLogger(getClass());
}
void unsetLogger(LoggerFactory loggerFactory) {
if (this.factory == loggerFactory) {
this.factory = null;
this.osgiLogger = null;
}
}
/**
* Set the {@link SessionLogger} that should be used to write the session log of
* the transformation. To write the log, the {@link SessionLogger} needs to have
* {@link SessionLogWriter} set.
*
* @param logger The {@link SessionLogger} that should be used to write the
* session log of the transformation.
*/
@Reference(name = "sessionLogger")
public void setSessionLogger(SessionLogger logger) {
this.logger = logger;
}
// Model 2 Text
@Reference(name = "m2mTransformers", cardinality = ReferenceCardinality.MULTIPLE)
public void registerM2mTransformer(Model2ModelRootTransformer transformer) {
this.m2mTransformers.add(transformer);
}
// Model 2 Text
@Reference(name = "m2tTransformers", cardinality = ReferenceCardinality.MULTIPLE)
public void registerM2tTransformer(Model2TextRootTransformer transformer) {
m2tTransformers.add(transformer);
}
/**
* Start the transformation within an OSGi context. The call of this method
* assumes that the {@link TransformerRegistry} instance is configured via OSGi
* component configuration.
*/
public void startTransformation() {
if (this.transformationStarted.compareAndSet(false, true)) {
start();
}
}
void start() {
try {
logger.info("Starting Model transformation ...");
// Model to Model transformation
for (Model2ModelRootTransformer model2ModelRootTransformer : m2mTransformers) {
logger.info("****************** Model to Model Transformation : {0} *******************************", model2ModelRootTransformer.getTransformationKey());
logger.info("** Executing M2M transformer : {0}", model2ModelRootTransformer.getClass().getTypeName());
model2ModelRootTransformer.setSessionLogger(logger);
model2ModelRootTransformer.m2mTransformation();
}
// Model to Text transformation
for (Model2TextRootTransformer model2TextRootTransformer : m2tTransformers) {
logger.info("****************** Model to Text Transformation : {0} ****************************", model2TextRootTransformer.getTransformationKey());
logger.info("** Executing M2T transformer : {0}", model2TextRootTransformer.getClass().getTypeName());
model2TextRootTransformer.setSessionLogger(logger);
model2TextRootTransformer.m2tTransformation();
}
} finally {
logger.info("Transformation execution session \"{0}\" completed.", this.sessionName);
stopSession();
}
}
/**
* Stop the current running session by deleting the configuration. Additionally
* the session logger is flushed and disposed.
*/
private void stopSession() {
// we need to flush the session log first, as deleting the configuration will
// trigger listeners that eventually kill the process, e.g. in headless mode
this.logger.flush(new File(this.logFilePath));
if (this.eventAdmin != null) {
HashMap<String, Object> properties = new HashMap<>();
properties.put(ServiceConstants.SESSION_ID, this.sessionName);
this.eventAdmin.sendEvent(new Event("org/eclipse/app4mc/transformation/DONE", properties));
}
}
// Convenience API to perform transformations outside an OSGi runtime
/**
* This method is intended to be used for triggering the transformation process
* outside the OSGi context.
*
* @param properties The properties needed to configure the transformation.
*/
public void startTransformation(Map<String, ?> properties) {
this.logFilePath = (String) properties.get(TransformationConstants.LOG_FILE);
this.sessionName = "single";
if (this.logger == null) {
this.logger = new SessionLogger();
}
start();
}
/**
* This method is intended to be used for triggering the transformation process
* outside the OSGi context.
*
* @param logFilePath the session log file location
*/
public void startTransformation(String logFilePath) {
this.logFilePath = logFilePath;
this.sessionName = "single";
if (this.logger == null) {
this.logger = new SessionLogger();
}
start();
}
}