/**
* <copyright> Copyright (c) 2008-2009 Jonas Helming, Maximilian Koegel modified by Olivier Barais. 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 </copyright>
*/
package fr.inria.diverse.k3.benchVM.synthesis.generic.modelchanger;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.eclipse.emf.common.util.TreeIterator;
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 fr.inria.diverse.k3.benchVM.synthesis.generic.common.ModelGeneratorUtil;
import fr.inria.diverse.k3.benchVM.synthesis.generic.common.attribute.AttributeHandler;
/**
* Helper class that takes work from <code>ModelChanger</code>.
* With the help of this class, <code>ModelChanger</code> only
* has to be aware of the current root EObject. All methods
* should be accessed in a way and <code>init()</code>
* has to be called every time before starting a changing process.
*
* @see ModelChanger
* @see #init(long, boolean)
*/
final class ModelChangerHelper {
/**
* Random-object to compute random values for deleting EObjects
* and setting their attributes and references.
*/
private Random random;
/**
* The amount of work in units as an integer, used by the
* <code>ModelChanger</code>'s monitor to show the correct
* progress in the progress bar.
*
* @see #getAmountOfWork()
*/
private int amountOfWork;
/**
* Specifies whether exceptions should be caught and logged during the changing
* process. Initialized during {@link #init(long, boolean)}.
*/
private boolean ignoreAndLog;
/**
* A set of RuntimeExceptions that occurred during the last changing process.
*/
private Set<RuntimeException> exceptionLog;
/**
* Initializes the helper to prepare it for the next changing process.
* All private fields get new values, old ones are discarded.
* This also initializes <code>AttributeHandler</code>.
*
* @param seed the seed value used to generate random values
* @param ignoreExceptions should exceptions be ignored and logged?
* @see AttributeHandler#setRandom(Random)
*/
protected void init(long seed, boolean ignoreExceptions) {
random = new Random(seed);
amountOfWork = 0;
ignoreAndLog = ignoreExceptions;
exceptionLog = new LinkedHashSet<RuntimeException>();
modelGeneratorUtil.attributeHandler.setRandom(random);
}
/**
* Retrieves all children, direct and indirect, and returns them
* as a set. The <code>amountOfWork</code> for the progress monitor
* is also computed in this method.
*
* @param root the root EObject of the hierarchy
* @return all direct and indirect contents of <code>root</code>
*/
protected Set<EObject> getAllChildren(EObject root) {
TreeIterator<EObject> allContents = root.eAllContents();
Set<EObject> result = new LinkedHashSet<EObject>();
while(allContents.hasNext()) {
result.add(allContents.next());
// count every element three times: once for deletion,
// once for setting attributes, once for setting references
amountOfWork += 3;
}
return result;
}
/**
* Returns the amount of work, that was computed before when
* obtaining all children with {@link #getAllChildren}.
*
* @return the amount of work in units as an integer
* @see #amountOfWork
* @see #getAllChildren
*/
protected int getAmountOfWork() {
return amountOfWork;
}
/**
* Sets a reference, if the upper bound allows it,
* using {@link ModelGeneratorUtil#setReference}.
*
* @param eObject the EObject to set the reference for
* @param referenceClass the EClass of EObjects that shall be referenced
* @param reference the EReference that shall be set
* @param allEObjects all possible EObjects that can be referenced
* @see ModelGeneratorUtil#setReference(EObject, EClass, EReference, Random, Set, boolean, Map)
*/
ModelGeneratorUtil modelGeneratorUtil =new ModelGeneratorUtil();
protected void setReference(EObject eObject, EClass referenceClass, EReference reference,
Map<EClass, List<EObject>> allEObjects) {
// check if the upper bound is reached
if(!modelGeneratorUtil.isValid(reference, eObject, exceptionLog, ignoreAndLog) ||
(!reference.isMany() && eObject.eIsSet(reference))) {
return;
}
modelGeneratorUtil.setReference(eObject, referenceClass, reference, random,
exceptionLog, ignoreAndLog, allEObjects);
}
/**
* Clears an EObject's feature, that is removes all objects from a many-valued
* feature. If the target is single-valued, nothing is done.
*
* @param eObject the EObject to clear the feature for
* @param feature the EStructuralFeature that shall be cleared
*/
protected void clear(EObject eObject, EStructuralFeature feature) {
if(eObject.eIsSet(feature)) {
if(feature.isMany()) {
modelGeneratorUtil.removePerCommand(eObject, feature, (Collection<?>) eObject.eGet(feature),
exceptionLog, ignoreAndLog);
} else {
modelGeneratorUtil.setPerCommand(eObject, feature, null,
exceptionLog, ignoreAndLog);
}
}
}
/**
* Sets attributes of an EObject using {@link ModelGeneratorUtil#setEObjectAttributes()}.
*
* @param eObject the EObject to set attributes for
* @see ModelGeneratorUtil#setEObjectAttributes(EObject, Random, Set, boolean)
*/
protected void setEObjectAttributes(EObject eObject) {
modelGeneratorUtil.setEObjectAttributes(eObject, random, exceptionLog, ignoreAndLog);
}
/**
* @return a random value, that specifies whether an EObject shall
* be deleted or not
*/
protected boolean randomDelete() {
return random.nextDouble() < 0.49;
}
/**
* Returns the Exception-Log of the <code>ModelChanger</code>.
* The log is cleared after every {@link #init}-call, i.e. before every changing process.
* The log will be empty if no RuntimeException occurred or <code>ignoreAndLog</code>
* was set to <code>false</code> in <code>init</code>.
*
* @return a set of RuntimeExceptions that occurred during the last changing process
*/
protected Set<RuntimeException> getExceptionLog() {
return exceptionLog;
}
/**
* Returns all valid non-containment references for an EObject
* using {@link ModelGeneratorUtil#getValidReferences(EObject, Set, boolean)}.
*
* @param eObject the EObject to retrieve valid EReferences for
* @return all valid references as a list
* @see ModelGeneratorUtil#getValidReferences(EObject, Set, boolean)
*/
protected List<EReference> getValidReferences(EObject eObject) {
return modelGeneratorUtil.getValidReferences(eObject, exceptionLog, ignoreAndLog);
}
/**
* Deletes an EObject using {@link ModelGeneratorUtil#delete(EObject, Set, boolean)}.
* @param eObject the EObject to delete
*/
protected void delete(EObject eObject) {
modelGeneratorUtil.delete(eObject, exceptionLog, ignoreAndLog);
}
/**
* Returns whether an EStructuralFeature is valid for a given EObject or not.
* This method uses {@link ModelGeneratorUtil#isValid}.
*
* @param eObject the EObject <code>feature</code> belongs to
* @param feature the EStructuralFeature in question
* @return whether <code>feature</code> is valid or not
*/
protected boolean isValid(EObject eObject, EStructuralFeature feature) {
return modelGeneratorUtil.isValid(feature, eObject, exceptionLog, ignoreAndLog);
}
}