/**
*
*/
package org.feature.multi.perspective.generator.viewmodel;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.feature.model.utilities.ResourceUtil;
import org.feature.multi.perspective.generator.GenerateProperties;
import org.feature.multi.perspective.mapping.viewmapping.Mapping;
import org.feature.multi.perspective.mapping.viewmapping.MappingModel;
import org.feature.multi.perspective.mapping.viewmapping.ViewmappingFactory;
import org.feature.multi.perspective.model.viewmodel.AbstractGroup;
import org.feature.multi.perspective.model.viewmodel.CoreGroup;
import org.feature.multi.perspective.model.viewmodel.Group;
import org.feature.multi.perspective.model.viewmodel.GroupModel;
import org.feature.multi.perspective.model.viewmodel.ViewPoint;
import org.feature.multi.perspective.model.viewmodel.ViewPointContainer;
import org.feature.multi.perspective.model.editor.editors.View;
import org.feature.multi.perspective.model.editor.editors.ViewCreator;
import org.feature.multi.perspective.model.editor.editors.algorithms.BruteForceAlgorithm;
import org.feature.multi.perspective.model.editor.editors.algorithms.IncrementalAlgorithm;
import org.feature.multi.perspective.utilities.GroupModelUtil;
import org.js.model.feature.Feature;
import org.js.model.feature.FeatureModel;
import org.js.model.feature.csp.FeatureModelAnalyzer;
import org.js.model.feature.csp.FeatureVariant;
/**
* Generates mappings between a featuremodel and a cluster model.
*
* @author <a href="mailto:info@juliaschroeter.de">Julia Schroeter</a>
*
*/
public class FeatureMappingGenerator extends AbstractGenerator {
private static Logger log = Logger.getLogger(FeatureMappingGenerator.class);
private int generatedConsistentVPs = 0;
private boolean isCanceled = false;
private int attempts = 0;
/**
* generate the mapping by combining all featuremodels with all clustermodels in the generated project. Be aware of
* when creating consistent mappings, the groupmodelis modified and must be persisted afterwards.
*/
public void generateMapping(GenerateProperties properties) {
ResourceSet set = new ResourceSetImpl();
List<FeatureModel> fms = getAllFeatureModels(set);
List<GroupModel> vms = getAllViewModels(set);
for (FeatureModel featureModel : fms) {
FeatureModelAnalyzer analyzer = new FeatureModelAnalyzer(featureModel);
for (int featuresPerGroup : assignedFeaturesPerGroup) {
if (properties.isReuseMapping()) {
// create the largest valid featuremapping and reuse it for all groupmodels
generateAndReuseFeatureMapping(set, featureModel, featuresPerGroup, analyzer, properties.isGenerateConsistentMapping());
if (isCanceled) {
log.info("No mapping created. The process was cancelled due to a time out.");
return;
}
} else {
// generate a new featuremapping for every group model
for (GroupModel groupModel : vms) {
generateMapping(featureModel, groupModel, featuresPerGroup, analyzer, false, properties.isGenerateConsistentMapping());
if (isCanceled) {
log.info("No mapping created. The process was cancelled due to a time out.");
return;
}
}
}
}
}
}
private void resetCancelled() {
isCanceled = false;
generatedConsistentVPs = 0;
}
private void generateAndReuseFeatureMapping(ResourceSet set, FeatureModel featureModel, int featuresPerGroup,
FeatureModelAnalyzer analyzer, boolean consistent) {
List<GroupModel> allGroupModels = getAllViewModels(set);
// find highest number of viewpoints a featuremapping will be generated for
GroupModel largestGroupModel = findGroupModelWithMostViewpoints(allGroupModels);
allGroupModels.remove(largestGroupModel);
// generate persisted largest featuremapping
MappingModel largestMapping =
generateLargestMapping(featureModel, largestGroupModel, featuresPerGroup, analyzer, consistent, false);
if (!isCanceled) {
// create wrapping viewpoint-group instances
List<ViewpointGroupWrapper> viewpointGroups = getWrappedViewpoints(largestGroupModel);
for (GroupModel gModel : allGroupModels) {
// for every groupmodel copy viewpount-group assignments
//copyViewpointGroupAssignment(gModel, viewpointGroups);
//saveGroupModel(gModel);
// copy the largest feature mapping and change references to each other groupmodel
MappingModel mappingCopy = EcoreUtil.copy(largestMapping);
exchangeGroupModel(mappingCopy, gModel);
exchangeElementMappings(mappingCopy, gModel);
// persist new featuremapping
saveFeatureMapping(mappingCopy, featureModel, gModel, featuresPerGroup);
}
}
}
private MappingModel generateLargestMapping(FeatureModel featureModel, GroupModel largestGroupModel, int featuresPerGroup,
FeatureModelAnalyzer analyzer, boolean bruteforceConsistent,
boolean heuristicConsistent) {
log.info("Try to generate largest feature mapping and reuse it.");
if (attempts > 10) {
isCanceled = true;
log.info("Generating cancelled because number of maximal attemps reached.");
return null;
}
MappingModel largestMapping =
generateMapping(featureModel, largestGroupModel, featuresPerGroup, analyzer, bruteforceConsistent, heuristicConsistent);
if (isCanceled) {
resetCancelled();
attempts++;
// try to regenerate mapping
return generateLargestMapping(featureModel, largestGroupModel, featuresPerGroup, analyzer, bruteforceConsistent,
heuristicConsistent);
}
return largestMapping;
}
private void exchangeElementMappings(MappingModel mappingCopy, GroupModel groupModel) {
List<AbstractGroup> allGroups = GroupModelUtil.getAllGroups(groupModel, false);
EList<Mapping> mappings = mappingCopy.getMappings();
for (Mapping mapping : mappings) {
EObject element = mapping.getViewgroup();
if (element instanceof CoreGroup) {
mapping.setViewgroup(groupModel.getCoreGroup());
} else if (element instanceof Group) {
Group oldGroup = (Group) element;
String oldGroupName = oldGroup.getName();
for (AbstractGroup newGroup : allGroups) {
if (newGroup.getName().equals(oldGroupName)) {
mapping.setViewgroup(newGroup);
break;
}
}
}
}
}
private void exchangeGroupModel(MappingModel mappingCopy, GroupModel groupModel) {
mappingCopy.setViewModel(groupModel);
}
private void copyViewpointGroupAssignment(GroupModel groupModel, List<ViewpointGroupWrapper> viewpointGroups) {
ViewModelGenerator vmGenerator = new ViewModelGenerator();
// all groups except the coregroup
List<AbstractGroup> allGroups = GroupModelUtil.getAllGroups(groupModel, true);
EList<ViewPoint> viewpoints = groupModel.getViewPointContainer().getViewPoints();
for (ViewPoint viewpoint : viewpoints) {
for (ViewpointGroupWrapper viewpointGroupWrapper : viewpointGroups) {
String vpName = viewpointGroupWrapper.getViewpointName();
if (vpName.equals(viewpoint.getName())) {
vmGenerator.removeViewPointFromGroups(viewpoint);
List<String> groupIds = viewpointGroupWrapper.getGroupIds();
assignVPtoGroups(viewpoint, groupIds, allGroups);
break;
}
}
}
}
private void assignVPtoGroups(ViewPoint viewPoint, List<String> groupIds, List<AbstractGroup> allGroups) {
for (String string : groupIds) {
for (AbstractGroup group : allGroups) {
if (group.getName().equals(string)) {
group.getViewPointReference().add(viewPoint);
break;
}
}
}
}
private List<ViewpointGroupWrapper> getWrappedViewpoints(GroupModel groupModel) {
EList<ViewPoint> viewPoints = groupModel.getViewPointContainer().getViewPoints();
List<ViewpointGroupWrapper> viewpointGroupWrappers = new ArrayList<ViewpointGroupWrapper>(viewPoints.size());
for (ViewPoint viewPoint : viewPoints) {
String vpName = viewPoint.getName();
ViewpointGroupWrapper wrapper = new ViewpointGroupWrapper(vpName);
EList<AbstractGroup> assignedGroups = viewPoint.getContainedInGroup();
for (AbstractGroup group : assignedGroups) {
String groupName = group.getName();
wrapper.addGroup(groupName);
}
viewpointGroupWrappers.add(wrapper);
}
return viewpointGroupWrappers;
}
private GroupModel findGroupModelWithMostViewpoints(List<GroupModel> allGroupModels) {
GroupModel groupModel = null;
int highestVPCount = 0;
for (GroupModel model : allGroupModels) {
ViewPointContainer viewPointContainer = model.getViewPointContainer();
if (viewPointContainer != null) {
List<ViewPoint> viewPoints = viewPointContainer.getViewPoints();
int size = viewPoints.size();
if (size > highestVPCount) {
highestVPCount = size;
groupModel = model;
}
}
}
return groupModel;
}
private MappingModel generateMapping(FeatureModel fm, GroupModel groupModel, int assignedFeatureCount,
FeatureModelAnalyzer analyzer, boolean bruteforceConsistent, boolean heuristicConsistent) {
MappingModel featuremapping = ViewmappingFactory.eINSTANCE.createMappingModel();
featuremapping.setFeatureModel(fm);
featuremapping.setViewModel(groupModel);
// map variant features to core group
FeatureVariant variant = analyzer.getOneVariant();
log.info("Core Group Features " + variant);
Set<Feature> selectedFeatures = variant.getSelectedFeatures();
CoreGroup coreGroup = groupModel.getCoreGroup();
Mapping coremapping = createCoreFeatureMapping(selectedFeatures, coreGroup);
featuremapping.getMappings().add(coremapping);
boolean isCoreViewPointValid =
isVPValidBruteforce(GroupModelUtil.getViewpointByName(coreViewpointName, groupModel), fm, groupModel, featuremapping);
log.info("Core Viewpoint is valid: " + isCoreViewPointValid);
// map all other features somewhere
Set<Feature> variableFeatures = analyzer.getAllFeatures();
List<AbstractGroup> allGroups = GroupModelUtil.getAllGroups(groupModel, false);
createVariableFeatureMapping(variableFeatures, allGroups, featuremapping, assignedFeatureCount);
mapUnmappedFeatures(featuremapping, groupModel);
if (bruteforceConsistent) {
checkMappingBruteForce(groupModel, featuremapping, fm);
} else if (heuristicConsistent) {
checkMappingHeuristic(groupModel, featuremapping, fm);
}
if (!isCanceled) {
saveGroupModel(groupModel);
saveFeatureMapping(featuremapping, fm, groupModel, assignedFeatureCount);
}
return featuremapping;
}
private void saveFeatureMapping(MappingModel featureMapping, FeatureModel featureModel, GroupModel groupModel,
int assignedFeatureCount) {
String fmFile = ResourceUtil.getFile(featureModel.eResource()).getName();
String viewModelFile = ResourceUtil.getFile(groupModel.eResource()).getName();
String type = fmFile + "_" + viewModelFile + param_FCount + assignedFeatureCount;
persistModel(featureMapping, type, "mtext", mappingFolder);
}
private void mapUnmappedFeatures(MappingModel featureMapping, GroupModel groupModel) {
FeatureModel featureModel = featureMapping.getFeatureModel();
List<AbstractGroup> allGroups = GroupModelUtil.getAllGroups(groupModel, false);
ViewCreator viewCreator = new ViewCreator(groupModel, featureModel, featureMapping);
Set<Feature> unmapped = viewCreator.getUnmappedFeatures(featureModel);
EList<Mapping> mappings = featureMapping.getMappings();
for (Feature feature : unmapped) {
int index = getRandomGenerator().nextInt(allGroups.size() - 1);
AbstractGroup group = allGroups.get(index);
Mapping elementMapping = ViewmappingFactory.eINSTANCE.createMapping();
elementMapping.setViewgroup(group);
elementMapping.getFeatures().add(feature);
mappings.add(elementMapping);
}
}
private void checkMappingBruteForce(GroupModel groupModel, MappingModel featureMapping, FeatureModel featureModel) {
List<ViewPoint> viewPoints = groupModel.getViewPointContainer().getViewPoints();
for (ViewPoint viewPoint : viewPoints) {
if (!coreViewpointName.equals(viewPoint.getName())) {
exchangeViewpoint(viewPoint, featureModel, groupModel, featureMapping, false);
if (isCanceled) {
break;
}
}
}
}
private void checkMappingHeuristic(GroupModel groupModel, MappingModel featureMapping, FeatureModel featureModel) {
List<ViewPoint> viewPoints = groupModel.getViewPointContainer().getViewPoints();
for (ViewPoint viewPoint : viewPoints) {
if (!coreViewpointName.equals(viewPoint.getName())) {
exchangeViewpoint(viewPoint, featureModel, groupModel, featureMapping, true);
if (isCanceled) {
break;
}
}
}
}
private void exchangeViewpoint(ViewPoint viewpoint, FeatureModel featureModel, GroupModel groupModel,
MappingModel featureMapping, boolean useHeuristic) {
ViewModelGenerator generator = new ViewModelGenerator();
boolean isValid = false;
if (useHeuristic) {
isValid = isVPValidHeuristic(viewpoint, featureModel, groupModel, featureMapping);
} else {
isValid = isVPValidBruteforce(viewpoint, featureModel, groupModel, featureMapping);
}
// time out set to 200 sek.
long endTimeMillis = System.currentTimeMillis() + 300000;
while (!isValid && !isCanceled) {
// saveFeatureMapping(featureMapping, featureModel, groupModel, 5);
generator.exchangeViewpoint(viewpoint, groupModel);
if (useHeuristic) {
isValid = isVPValidHeuristic(viewpoint, featureModel, groupModel, featureMapping);
} else {
isValid = isVPValidBruteforce(viewpoint, featureModel, groupModel, featureMapping);
}
if (System.currentTimeMillis() > endTimeMillis && generatedConsistentVPs == 0) {
isCanceled = true;
}
}
if (isValid) {
generatedConsistentVPs++;
String logMsg = "FeatureMappingGen ";
logMsg += viewpoint.getName();
logMsg += " contained in ";
EList<AbstractGroup> containedInGroup = viewpoint.getContainedInGroup();
for (AbstractGroup group : containedInGroup) {
logMsg += group.getName() + ", ";
}
log.info(logMsg);
}
}
private boolean isVPValidBruteforce(ViewPoint vp, FeatureModel featureModel, GroupModel groupModel, MappingModel featureMapping) {
boolean result = false;
ViewCreator viewCreator = new ViewCreator(groupModel, featureModel, featureMapping);
List<View> views = viewCreator.getViews();
BruteForceAlgorithm bruteForce = new BruteForceAlgorithm(groupModel, views, featureModel);
result = bruteForce.isViewpointConsistent(vp);
log.debug(vp.getName() + " is valid in bruteforce: " + result);
return result;
}
private boolean isVPValidHeuristic(ViewPoint vp, FeatureModel featureModel, GroupModel groupModel, MappingModel featureMapping) {
boolean result = false;
ViewCreator viewCreator = new ViewCreator(groupModel, featureModel, featureMapping);
List<View> views = viewCreator.getViews();
IncrementalAlgorithm incremental = new IncrementalAlgorithm(groupModel, views, featureModel);
result = incremental.checkViewPoint(vp);
log.debug(vp.getName() + " is valid in bruteforce: " + result);
return result;
}
private Mapping createCoreFeatureMapping(Set<Feature> coreFeatures, CoreGroup coreGroup) {
Mapping elementMapping = ViewmappingFactory.eINSTANCE.createMapping();
elementMapping.setViewgroup(coreGroup);
elementMapping.getFeatures().addAll(coreFeatures);
return elementMapping;
}
private void createVariableFeatureMapping(Set<Feature> variableFeatures, List<AbstractGroup> allGroups, MappingModel featuremapping,
int assignedFeatureCount) {
EList<Mapping> mappings = featuremapping.getMappings();
int numberFeatures = variableFeatures.size();
Feature[] featureArray = variableFeatures.toArray(new Feature[numberFeatures]);
if (numberFeatures > assignedFeatureCount) {
for (AbstractGroup group : allGroups) {
int randomFeatureCount = 0;
while (randomFeatureCount == 0) {
randomFeatureCount = getRandomGenerator().nextInt(assignedFeatureCount);
}
List<Feature> features = new ArrayList<Feature>(randomFeatureCount);
for (int i = 0; i < randomFeatureCount; i++) {
int index = getRandomGenerator().nextInt(numberFeatures - 1);
features.add(featureArray[index]);
}
Mapping elementMapping = ViewmappingFactory.eINSTANCE.createMapping();
elementMapping.setViewgroup(group);
elementMapping.getFeatures().addAll(features);
mappings.add(elementMapping);
}
}
}
}