package org.js.model.feature.quality.assurance.analyze; import java.util.*; import org.js.model.feature.*; import org.js.model.feature.edit.FeatureModelHelper; public class FeatureBasedStructureAnalyzer extends StructureAnalyzer { /** * Create a new FeatureBasedStructureAnalyzer with all capabilities * @param models * @param model * @param feature * @throws Exception Throws, if there is any kind of inconsistency within the parameters */ public FeatureBasedStructureAnalyzer(Set<FeatureModel> models, FeatureModel model, Feature feature) throws Exception { super(models, model, feature); } /** * Reset the test environment (models, model feature) * @param models * @param model * @param feature * @return <code>True</code> if resetting was successful. If resetting was not successful, * the former state will be rolled back and this method returns <code>false</code>. */ public boolean resetAll(Set<FeatureModel> models, FeatureModel model, Feature feature) { Set<FeatureModel> oldModels = getModels(); FeatureModel oldModel = getModel(); Feature oldFeature = getFeature(); boolean success = true; setModels(models); success = setModel(model); if(!success) { setModels(oldModels); setModel(oldModel); setFeature(oldFeature); return false; } success = setFeature(feature); if(!success) { setModels(oldModels); setModel(oldModel); setFeature(oldFeature); return false; } return true; } /** * Reset the feature under test * @param feature * @return <code>True</code> if resetting was successful. If resetting was not successful, * the former state will be rolled back and this method returns <code>false</code>. */ public boolean resetFeature(Feature feature) { return setFeature(feature); } /** * Identifies all models that contain the feature under test * @return A set of models that contain the feature under test. Returns null if the result set * is not defined. */ public Set<FeatureModel> getFeatureModelsContainingFeature() { if(!isModelsSet() || !isFeatureSet()) return null; Set<FeatureModel> results = new HashSet<FeatureModel>(); for (FeatureModel currentModel : getModels()) { FeatureModelHelper currentModelHelper = new FeatureModelHelper(currentModel); Feature concreteFeature = currentModelHelper.getFeature(getFeature().getId()); if(concreteFeature != null) { if(concreteFeature.getConfigurationState() != FeatureState.DESELECTED) results.add(currentModel); } } return results; } /** * Identifies the feature as mandatory or optional * @return <code>True</code> if the feature is mandatory, else <code>false</code>. * @throws Exception If there is no model or feature that has been set. */ public boolean isFeatureMandatory() throws Exception { if(!isModelSet() || !isFeatureSet()) throw new Exception("At least the model or feature is not set."); // a feature is mandatory if the parent group requires the selection // of at least the amount of features that this group contains. boolean isMandatory = true; // per default, a feature is mandatory (e.g. root feature) FeatureModelHelper modelHelper = new FeatureModelHelper(getModel()); // is this feature the root feature of the model? ...else look up in groups if(getModel().getRoot() == getFeature()) { // isMandatory = true; (it's already true by default) return isMandatory; } // find group this feature is part of boolean readyToBreak = false; Set<Feature> allFeatures = modelHelper.getAllFeatures(); for (Feature f : allFeatures) { Set<Group> allGroupsOfFeature = new HashSet<Group>(); allGroupsOfFeature.addAll(f.getGroups()); for (Group g : allGroupsOfFeature) { Set<Feature> allFeaturesOfGroup = new HashSet<Feature>(); allFeaturesOfGroup.addAll(g.getChildFeatures()); for (Feature f2 : allFeaturesOfGroup) { if(f2 == getFeature()) { readyToBreak = true; if(allFeaturesOfGroup.size() > g.getMinCardinality()) { isMandatory = false; } break; } } if(readyToBreak) break; } if(readyToBreak) break; } return isMandatory; } /** * Get all Feature Constraints that affect the selection state of the feature * @return */ public Set<FeatureConstraint> getFeatureConstraintsAffectingFeature() { Set<FeatureConstraint> results = new HashSet<FeatureConstraint>(); results.addAll(getFeatureConstraintsAffectingFeatureInAnyOperand()); for (Feature feature : getSuborderedFeatures()) { results.addAll(getFeatureConstraintsAffectingFeatureInImplyRightOperand(feature)); } return results; } /** * Get all feature constraints that directly affect the selection state of the feature under test * @return */ public Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInAnyOperand() { if(!isFeatureSet()) return null; return getFeatureConstraintsAffectingFeatureInAnyOperand(getFeature()); } /** * Get all feature constraints that directly affect the selection state of the given feature * @param feature * @return */ private Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInAnyOperand(Feature feature) { Set<FeatureConstraint> results = new HashSet<FeatureConstraint>(); results.addAll(getFeatureConstraintsAffectingFeatureInImplyRightOperand(feature)); results.addAll(getFeatureConstraintsAffectingFeatureInImplyLeftOperand(feature)); results.addAll(getFeatureConstraintsAffectingFeatureInExcludeRightOperand(feature)); results.addAll(getFeatureConstraintsAffectingFeatureInExcludeLeftOperand(feature)); return results; } /** * Get all imply feature constraints that contain the feature under test in the right operand. * @return */ public Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInImplyRightOperand() { if(!isFeatureSet()) return null; return getFeatureConstraintsAffectingFeatureInImplyRightOperand(getFeature()); } /** * Get all imply feature constraints that contain the feature in the right operand. * @param feature * @return */ private Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInImplyRightOperand(Feature feature) { if(!isModelSet()) return null; FeatureModelHelper fmh = new FeatureModelHelper(getModel()); Set<FeatureConstraint> allconstraints = fmh.getAllFeatureConstraints(); Set<Imply> allimplys = new HashSet<Imply>(); for (FeatureConstraint fc : allconstraints) { if(fc instanceof Imply) { allimplys.add((Imply) fc); } } Set<FeatureConstraint> results = new HashSet<FeatureConstraint>(); for (Imply imply : allimplys) { if(imply.getRightOperand() == feature) results.add(imply); } return results; } /** * Get all imply feature constraints that contain the feature under test in the left operand. * @return */ public Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInImplyLeftOperand() { if(!isFeatureSet()) return null; return getFeatureConstraintsAffectingFeatureInImplyLeftOperand(getFeature()); } /** * Get all imply feature constraints that contain the feature in the left operand. * @param feature * @return */ private Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInImplyLeftOperand(Feature feature) { if(!isModelSet()) return null; FeatureModelHelper fmh = new FeatureModelHelper(getModel()); Set<FeatureConstraint> allconstraints = fmh.getAllFeatureConstraints(); Set<Imply> allimplys = new HashSet<Imply>(); for (FeatureConstraint fc : allconstraints) { if(fc instanceof Imply) { allimplys.add((Imply) fc); } } Set<FeatureConstraint> results = new HashSet<FeatureConstraint>(); for (Imply imply : allimplys) { if(imply.getLeftOperand() == feature) results.add(imply); } return results; } /** * Get all exclude feature constraints that contain the feature under test in the right operand. * @return */ public Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInExcludeRightOperand() { if(!isFeatureSet()) return null; return getFeatureConstraintsAffectingFeatureInExcludeRightOperand(getFeature()); } /** * Get all exclude feature constraints that contain the feature in the right operand. * @param feature * @return */ private Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInExcludeRightOperand(Feature feature) { if(!isModelSet()) return null; FeatureModelHelper fmh = new FeatureModelHelper(getModel()); Set<FeatureConstraint> allconstraints = fmh.getAllFeatureConstraints(); Set<Exclude> allexcludes = new HashSet<Exclude>(); for (FeatureConstraint fc : allconstraints) { if(fc instanceof Exclude) { allexcludes.add((Exclude) fc); } } Set<FeatureConstraint> results = new HashSet<FeatureConstraint>(); for (Exclude exclude : allexcludes) { if(exclude.getRightOperand() == feature) results.add(exclude); } return results; } /** * Get all exclude feature constraints that contain the feature under test in the left operand. * @return */ public Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInExcludeLeftOperand() { if(!isFeatureSet()) return null; return getFeatureConstraintsAffectingFeatureInExcludeLeftOperand(getFeature()); } /** * Get all exclude feature constraints that contain the feature in the left operand. * @param feature * @return */ private Set<FeatureConstraint> getFeatureConstraintsAffectingFeatureInExcludeLeftOperand(Feature feature) { if(!isModelSet()) return null; FeatureModelHelper fmh = new FeatureModelHelper(getModel()); Set<FeatureConstraint> allconstraints = fmh.getAllFeatureConstraints(); Set<Exclude> allexcludes = new HashSet<Exclude>(); for (FeatureConstraint fc : allconstraints) { if(fc instanceof Exclude) { allexcludes.add((Exclude) fc); } } Set<FeatureConstraint> results = new HashSet<FeatureConstraint>(); for (Exclude exclude : allexcludes) { if(exclude.getLeftOperand() == feature) results.add(exclude); } return results; } /** * Get all sub ordered features of the feature under test * @return */ private Set<Feature> getSuborderedFeatures() { if(!isFeatureSet()) return null; return getSuborderedFeatures(getFeature()); } /** * Get all sub ordered features of the feature parameter * @param feature * @return */ private Set<Feature> getSuborderedFeatures(Feature feature) { Set<Group> groups = new HashSet<Group>(); groups.addAll(feature.getGroups()); Set<Feature> results = new HashSet<Feature>(); for (Group group : groups) { Set<Feature> childfeatures = new HashSet<Feature>(); childfeatures.addAll(group.getChildFeatures()); for (Feature cf : childfeatures) { // add this child feature and get all sub ordered features via recursion results.add(cf); results.addAll(getSuborderedFeatures(cf)); } } return results; } }