blob: 7fe996c1310922ad3c8afbe1d180aa2f168dd16d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Edgar Mueller - initial API and implementation
******************************************************************************/
package org.eclipse.emf.emfstore.internal.modelmutator.mutation;
import static org.eclipse.emf.emfstore.internal.modelmutator.mutation.MutationPredicates.HAS_GROUP_FEATURE_MAP_ENTRY_TYPE;
import static org.eclipse.emf.emfstore.internal.modelmutator.mutation.MutationPredicates.IS_NON_EMPTY_FEATURE_MAP;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.change.FeatureMapEntry;
import org.eclipse.emf.ecore.change.impl.FeatureMapEntryImpl;
import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl.ContainmentUpdatingFeatureMapEntry;
import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl.SimpleFeatureMapEntry;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMap.Entry;
import org.eclipse.emf.ecore.util.FeatureMap.Entry.Internal;
import org.eclipse.emf.emfstore.modelmutator.ESFeatureMapValueMutation;
import org.eclipse.emf.emfstore.modelmutator.ESModelMutatorUtil;
import org.eclipse.emf.emfstore.modelmutator.ESMutationException;
/**
* A mutation, which changes the value of {@link org.eclipse.emf.ecore.change.FeatureMapEntry feature map entries}.
*
* @author emueller
*
*/
public class FeatureMapValueMutation extends StructuralFeatureMutation<ESFeatureMapValueMutation>
implements ESFeatureMapValueMutation {
/**
* Creates a new mutation with the specified {@code util}.
*
* @param util The model mutator util used for accessing the model to be mutated.
*/
public FeatureMapValueMutation(ESModelMutatorUtil util) {
super(util);
addTargetFeaturePredicate();
addOriginalFeatureValuePredicate();
}
/**
* Creates a new mutation with the specified {@code util} and the {@code selector}.
*
* @param util The model mutator util used for accessing the model to be mutated.
* @param selector The target selector for selecting the target container and feature.
*/
public FeatureMapValueMutation(ESModelMutatorUtil util, MutationTargetSelector selector) {
super(util, selector);
addTargetFeaturePredicate();
addOriginalFeatureValuePredicate();
}
private void addTargetFeaturePredicate() {
getTargetContainerSelector().getTargetFeaturePredicates().add(HAS_GROUP_FEATURE_MAP_ENTRY_TYPE);
}
private void addOriginalFeatureValuePredicate() {
getTargetContainerSelector().getOriginalFeatureValuePredicates().add(IS_NON_EMPTY_FEATURE_MAP);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.modelmutator.mutation.Mutation#clone()
*/
@Override
public Mutation clone() {
return new FeatureMapValueMutation(getUtil(), getTargetContainerSelector());
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.modelmutator.mutation.Mutation#apply()
*/
@Override
public void apply() throws ESMutationException {
getTargetContainerSelector().doSelection();
final List<FeatureMap.Entry> currentEntries = getFeatureMapEntries();
final FeatureMap.Entry entry = getRandomFeatureMapEntryOfTarget(currentEntries);
final EStructuralFeature currentFeatureKey = entry.getEStructuralFeature();
if (isReference(currentFeatureKey) && !isContainmentReference(currentFeatureKey)) {
final EObject currentValue = EObject.class.cast(entry.getValue());
final EObject selectedEObject = selectEObject(currentValue.eClass());
if (selectedEObject != null) {
if (FeatureMapEntry.class.isInstance(entry)) {
FeatureMapEntry.class.cast(entry).setReferenceValue(selectedEObject);
} else if (SimpleFeatureMapEntry.class.isInstance(entry)) {
final Internal createEntry = ((SimpleFeatureMapEntry) entry).createEntry(selectedEObject);
if (!currentEntries.contains(createEntry)) {
currentEntries.set(currentEntries.indexOf(entry), createEntry);
}
} else {
// TODO: use logger
// System.out.println(MessageFormat.format(
// "Unhandled Feature Map Entry type {0}", entry.getClass()));
}
}
} else if (isContainmentReference(currentFeatureKey)) {
if (FeatureMapEntryImpl.class.isInstance(entry)) {
final FeatureMapEntryImpl featureMapEntry = FeatureMapEntryImpl.class.cast(entry);
featureMapEntry.setReferenceValue(
createOfType(
EReference.class.cast(featureMapEntry.getEStructuralFeature()).getEReferenceType()));
}
} else if (ContainmentUpdatingFeatureMapEntry.class.isInstance(entry)) {
// TODO
// final ContainmentUpdatingFeatureMapEntry featureMapEntry = ContainmentUpdatingFeatureMapEntry.class
// .cast(entry);
// System.out.println("FeatureMapEntry: " + featureMapEntry.getValue());
} else if (EAttribute.class.isInstance(currentFeatureKey)) {
// System.out.println("SET ATTRIBUTE");
} else {
// TODO
// System.out.println(MessageFormat.format(
// "Unhandled containment Feature Map Entry {0}", entry.getClass()));
}
}
public EObject createOfType(EClass eClass) {
final EObject eObjectToAdd = EcoreUtil.create(eClass);
getUtil().setEObjectAttributes(eObjectToAdd);
return eObjectToAdd;
}
private EObject selectEObject(EClass eClass) {
final Map<EClass, List<EObject>> allObjects = ESModelMutatorUtil
.getAllObjects(getUtil()
.getModelMutatorConfiguration()
.getRootEObject());
final List<EObject> possibleObjects = allObjects.get(eClass);
EObject selectedEObject = null;
if (possibleObjects != null && !possibleObjects.isEmpty()) {
while (!possibleObjects.isEmpty() && selectedEObject == null) {
selectedEObject = possibleObjects.get(getRandom().nextInt(possibleObjects.size()));
if (!eObjectFits(selectedEObject)) {
possibleObjects.remove(selectedEObject);
selectedEObject = null;
}
}
}
return selectedEObject;
}
private boolean eObjectFits(EObject eObject) {
final EClass eClass = eObject.eClass();
final EList<EStructuralFeature> eAllStructuralFeatures = eClass.getEAllStructuralFeatures();
for (final EStructuralFeature feature : eAllStructuralFeatures) {
if (feature.getEType().equals(EcorePackage.eINSTANCE.getEFeatureMap())) {
return false;
}
}
return true;
}
private static boolean isReference(EStructuralFeature feature) {
return EReference.class.isInstance(feature);
}
private static boolean isContainmentReference(EStructuralFeature feature) {
return EReference.class.isInstance(feature)
&& EReference.class.cast(feature).isContainment();
}
@SuppressWarnings("unchecked")
private List<Entry> getFeatureMapEntries() {
return (List<FeatureMap.Entry>) getTargetObject().eGet(getTargetFeature());
}
private FeatureMap.Entry getRandomFeatureMapEntryOfTarget(List<Entry> currentEntries) {
final int pickIndex = getRandom().nextInt(currentEntries.size());
return currentEntries.get(pickIndex);
}
}