/******************************************************************************* * 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); } }