package org.feature.transform.splot2fm;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.feature.model.utilities.FeatureModelInit;
import org.feature.transform.splot2fm.utils.SXFMUtil;
import org.js.model.feature.Constraint;
import org.js.model.feature.Feature;
import org.js.model.feature.FeatureModel;
import org.js.model.feature.Group;
import org.js.model.feature.edit.FeatureModelHelper;
import constraints.BooleanVariable;
import constraints.PropositionalFormula;
import fm.FeatureGroup;
import fm.FeatureModelException;
import fm.FeatureTreeNode;
import fm.GroupedFeature;
import fm.SolitaireFeature;
public class SXFM2FMTransformator {
private static Logger log = Logger.getLogger(SXFM2FMTransformator.class);
private static String groupIdPrefix = "group_";
private static String sxfmModelExtension = "xml";
public static String efm_fileextension = "eft";
public static void parseFiles(List<IFile> files, String featureModelExtension) {
for (IFile iFile : files) {
IPath filePath = iFile.getRawLocation();
String xmlExtension = filePath.getFileExtension();
if (filePath != null && StringUtils.equalsIgnoreCase(sxfmModelExtension, xmlExtension)) {
String sxfmFile = filePath.toOSString();
IPath fmFilePath = filePath.removeFileExtension();
fmFilePath = fmFilePath.addFileExtension(featureModelExtension);
String fmFile = fmFilePath.toOSString();
transform(sxfmFile, fmFile);
}
}
}
public static void transform(String sxfmFile, String fmFile) {
try {
fm.FeatureModel sxfmModel = SXFMUtil.initSXFMFeatureModel(sxfmFile);
FeatureModel fmModel = FeatureModelInit.initFeatureModel();
String modelName = sxfmModel.getName();
fmModel.setName(modelName);
log.info("----------------------------------------------------");
log.info("Start Transformation--------------------------------");
log.info("----------------------------------------------------");
log.info("Input: '" + sxfmFile + "'");
log.info("----------------------------------------------------");
long start = System.currentTimeMillis();
transform(sxfmModel, fmModel);
postprocess(fmModel);
// persist Model before transforming constraints
FeatureModelInit.persistFMFeatureModel(fmModel, fmFile);
transformConstraints(sxfmModel, fmModel);
FeatureModelInit.persistFMFeatureModel(fmModel, fmFile);
long end = System.currentTimeMillis();
log.info("----------------------------------------------------");
log.info("Output: '" + fmFile + "'");
log.info("----------------------------------------------------");
log.info("Stopp Transformation--------------------------------");
log.info("----------------------------------------------------");
log.info("Transformation took " + (end - start) + " ms.");
analyseModel(fmModel, sxfmModel);
} catch (FeatureModelException e) {
log.error("The selected file '" + sxfmFile + "' is not a SXFM feature model and cannot be transformed.");
}
}
private static void transformConstraints(fm.FeatureModel sxfmModel, FeatureModel fmModel) {
transformConstraintsintoExpression(sxfmModel, fmModel);
}
private static void postprocess(FeatureModel fmModel) {
// correct feature names and ids
FeatureModelHelper helper = new FeatureModelHelper(fmModel);
Set<Feature> allFeatures = helper.getAllFeatures();
for (Feature feature : allFeatures) {
String name = feature.getName();
feature.setName(normalizeIdentifier(name));
String id = feature.getId();
feature.setId(normalizeIdentifier(id));
}
Set<Group> allGroups = helper.getAllGroups();
for (Group group : allGroups) {
String id = group.getId();
group.setId(normalizeIdentifier(id));
}
}
private static String normalizeIdentifier(String element) {
element = StringUtils.replace(element, "/", "-");
return element;
}
private static void analyseModel(FeatureModel fmModel, fm.FeatureModel sxfmModel) {
FeatureModelHelper featureModelHelper = new FeatureModelHelper(fmModel);
int newFeatures = featureModelHelper.getAllFeatures().size();
int oldFeatures = sxfmModel.countFeatures();
log.debug("Features parsed : " + oldFeatures);
log.debug("Features created : " + newFeatures);
log.debug("----------------------------------------------------");
int oldConstraints = sxfmModel.countConstraints();
int newConstraints = fmModel.getConstraints().size();
log.debug("Constraints parsed : " + oldConstraints);
log.debug("Constraints created : " + newConstraints);
log.debug("----------------------------------------------------");
log.debug("----------------------------------------------------");
}
private static void transform(fm.FeatureModel sxfmModel, FeatureModel fmModel) {
Assert.isNotNull(sxfmModel);
Assert.isNotNull(fmModel);
log.info("Transformation of Featuremodel '" + sxfmModel.getName() + "'.");
FeatureTreeNode sxfmRoot = sxfmModel.getRoot();
String rootName = sxfmRoot.getName();
String id = sxfmRoot.getID();
Feature fmRootFeature = FeatureModelInit.createRootFeature(fmModel, rootName, id);
log.info("Root Node '" + rootName + "' created.");
// transformMetadata(sxfmModel, fmRootFeature);
for (int i = 0; i < sxfmRoot.getChildCount(); i++) {
FeatureTreeNode node = (FeatureTreeNode) sxfmRoot.getChildAt(i);
transformFeatures(node, fmRootFeature);
}
Set<Feature> allFeatures = FeatureModelInit.getAllFeatures(fmModel);
FeatureModelInit.makeFeatureIdsUnique(allFeatures);
}
private static void transformFeatures(FeatureTreeNode featureNode, Feature fmParent) {
// feature is direct child of parent feature -> create single feature
// group
if (featureNode instanceof SolitaireFeature) {
log.debug("SolitaireFeature '" + featureNode.getName() + "' found.");
SolitaireFeature solitaireFeature = (SolitaireFeature) featureNode;
Feature fmFeature = transformSolitaireFeature(solitaireFeature, fmParent);
for (int i = 0; i < featureNode.getChildCount(); i++) {
FeatureTreeNode node = (FeatureTreeNode) featureNode.getChildAt(i);
transformFeatures(node, fmFeature);
}
// feature is child of feature group -> 1. create group, 2. add
// further feature to this group
} else if (featureNode instanceof GroupedFeature) {
log.debug("GroupedFeature '" + featureNode.getName() + "' found.");
GroupedFeature groupedFeature = (GroupedFeature) featureNode;
String groupId = groupedFeature.getGroup().getID();
Feature newFeature = transformGroupedFeature(groupedFeature, fmParent, groupId);
for (int i = 0; i < groupedFeature.getChildCount(); i++) {
FeatureTreeNode node = (FeatureTreeNode) featureNode.getChildAt(i);
transformFeatures(node, newFeature);
}
} else if (featureNode instanceof FeatureGroup) {
FeatureGroup fGroup = (FeatureGroup) featureNode;
log.debug("FeatureGroup " + fGroup.getName() + "[" + fGroup.getMin() + "," + fGroup.getMax() + "]" + " found.");
transformGroupNode(fGroup, fmParent);
}
}
private static void transformGroupNode(FeatureGroup featureGroup, Feature parentFeature) {
int max = featureGroup.getMax();
int min = featureGroup.getMin();
String id = featureGroup.getID();
FeatureModelInit.createFeatureGroup(parentFeature, min, max, id);
for (int i = 0; i < featureGroup.getChildCount(); i++) {
FeatureTreeNode node = (FeatureTreeNode) featureGroup.getChildAt(i);
transformFeatures(node, parentFeature);
}
}
private static Feature transformSolitaireFeature(SolitaireFeature sxfmNode, Feature fmParent) {
String name = sxfmNode.getName();
String id = sxfmNode.getID();
boolean optional = sxfmNode.isOptional();
String groupId = groupIdPrefix + id;
Feature fmSolitairefeature = FeatureModelInit.createSingleFeature(fmParent, name, id, optional, groupId);
return fmSolitairefeature;
}
private static Feature transformGroupedFeature(GroupedFeature sxfmNode, Feature fmParent, String groupId) {
String name = sxfmNode.getName();
String id = sxfmNode.getID();
Feature fmFeature = FeatureModelInit.createGroupFeature(fmParent, name, id, groupId);
return fmFeature;
}
private static void transformConstraintsintoExpression(fm.FeatureModel sxfmModel, FeatureModel fmModel) {
Assert.isNotNull(sxfmModel);
Assert.isNotNull(fmModel);
URI uri = EcoreUtil.getURI(fmModel);
Collection<PropositionalFormula> constraints = sxfmModel.getConstraints();
EList<Constraint> fmConstraints = fmModel.getConstraints();
FeatureModelHelper helper = new FeatureModelHelper(fmModel);
Set<Feature> allFeatures = helper.getAllFeatures();
for (PropositionalFormula propositionalFormula : constraints) {
String formula = propositionalFormula.getFormula();
log.debug("Propositional Formula: " + formula);
Collection<BooleanVariable> variables = propositionalFormula.getVariables();
// find ~ and replace
formula = StringUtils.replace(formula, "~", "not ");
//
// // find ids and replace by featurename
// for (BooleanVariable booleanVariable : variables) {
// String id = booleanVariable.getID();
// boolean replaced = false;
//
// for (Feature feature : allFeatures) {
// String featureId = feature.getId();
//
// if (StringUtils.equalsIgnoreCase(id, featureId)) {
// String featureName = feature.getName();
// String regex = "^" + id + "[\\s|)]|[~|\\s|(]" + id + "[\\s|)]|[~|\\s|(]" + id + "$|^id$";
// Pattern pattern = Pattern.compile(regex);
// Matcher matcher = pattern.matcher(formula);
// while (matcher.find()) {
// MatchResult result = matcher.toMatchResult();
// int start = result.start();
// int end = result.end();
// formula = replace(formula, id, featureName, start, end);
// }
// replaced = true;
// break;
// }
// }
// if (!replaced) {
// log.error("Could not replace the feature id '" + id + "' in the model constraints.");
// }
// }
log.debug("Transformed Formula: " + formula);
Constraint newConstraint = transformConstraint(formula, uri);
if (newConstraint != null) {
fmConstraints.add(newConstraint);
}
}
}
private static Constraint transformConstraint(String formula, URI uri) {
Constraint constraint = TextExpressionParser.createFeatureConstraint(formula, uri);
return constraint;
}
private static String replace(String input, String searchString, String replacement, int minPosition, int maxPosition) {
String substring = StringUtils.substring(input, minPosition, maxPosition);
String replacedSubstring = StringUtils.replace(substring, searchString, replacement);
String begin = StringUtils.substring(input, 0, minPosition);
String end = StringUtils.substring(input, maxPosition);
String result = begin + replacedSubstring + end;
return result;
}
}