Commit 06a7e2c3 authored by Erwan Bousse's avatar Erwan Bousse
Browse files

Versionning everything

parent cf54973e
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
id="application"
point="org.eclipse.core.runtime.applications">
<application>
<run
class="fancyemfcloning.benchmark.generator.main.Application">
</run>
</application>
</extension>
</plugin>
package fancyemfcloning.benchmark.generator;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.ResourceSet;
import fancyemfcloning.benchmark.base.BenchmarkMaterial;
import fancyemfcloning.benchmark.base.MetamodelMetrics;
import fancyemfcloning.benchmark.base.ModelCreator;
import fr.inria.diverse.cloning.cloner.common.CloningMaterial;
import fr.inria.diverse.cloning.cloner.util.EcoreHelper;
import fr.inria.diverse.cloning.materialgenerator.util.CodeGeneration;
public class BenchmarkMaterialGenerator {
private static final String[] cloningNames = { "Deep", "MutClassOnly" };
public static MetamodelMetrics computeMetrics(ResourceSet metamodel) {
int mutableProperties = 0;
int mutableAttributes = 0;
int mutableReferences = 0;
int totalProperties = 0;
int totalAttributes = 0;
int totalReferences = 0;
int numberOfClasses = 0;
for (EClass c : EcoreHelper.findEClasses(metamodel)) {
numberOfClasses++;
for (EStructuralFeature f : c.getEAllStructuralFeatures()) {
totalProperties++;
if (f.getName().endsWith("_m"))
mutableProperties++;
if (f instanceof EReference) {
totalReferences++;
if (f.getName().endsWith("_m"))
mutableReferences++;
}
if (f instanceof EAttribute) {
totalAttributes++;
if (f.getName().endsWith("_m"))
mutableAttributes++;
}
}
}
return new MetamodelMetrics(totalProperties, totalReferences, totalAttributes, mutableProperties,
mutableReferences, mutableAttributes, numberOfClasses);
}
public static void generate(List<String> metamodelsnames, List<ResourceSet> metamodels, File outputFolder) {
// Computing the class name
String className = "BenchmarkMaterialImpl";
String packageFullName = "cloningbenchmark";
try {
// Preparing the output file and the printer
File outputDir = new File(outputFolder, packageFullName);
outputDir.mkdirs();
File outputFile = new File(outputDir, className + ".java");
outputFile.createNewFile();
PrintStream printer = new PrintStream(outputFile);
String header = "package " + packageFullName + ";\n";
String imports = "";
String classbody = "";
// ModelCreator Interface and EObject imports
imports += "import " + ModelCreator.class.getCanonicalName() + ";\n";
imports += "import " + BenchmarkMaterial.class.getCanonicalName() + ";\n";
imports += "import " + CloningMaterial.class.getCanonicalName() + ";\n";
imports += "import " + List.class.getCanonicalName() + ";\n";
imports += "import " + ArrayList.class.getCanonicalName() + ";\n";
imports += "import " + MetamodelMetrics.class.getCanonicalName() + ";\n";
// Class declaration
classbody += "public class " + className + " implements " + BenchmarkMaterial.class.getSimpleName()
+ " {\n";
// getMetamodelsNames
classbody += "public List<String> getMetamodelsName() {\n";
classbody += "List<String> result = new ArrayList<String>();\n";
for (String mmname : metamodelsnames) {
classbody += "result.add(\"" + mmname + "\");\n";
}
classbody += "return result;\n";
classbody += "}\n";
// getCloningNames
classbody += "public List<String> getCloningNames() {\n";
classbody += "List<String> result = new ArrayList<String>();\n";
for (String c : cloningNames) {
classbody += "result.add(\"" + c + "\");\n";
}
classbody += "return result;\n";
classbody += "}\n";
// getModelCreator
classbody += "public ModelCreator getModelCreator(String metamodelName) {\n";
classbody += "switch (metamodelName.toLowerCase()) {\n";
for (String mmname : metamodelsnames) {
imports += "import " + mmname.toLowerCase() + "modelcreator." + CodeGeneration.firstCharUp(mmname)
+ "ModelCreator;\n";
classbody += "case \"" + mmname.toLowerCase() + "\":\n";
classbody += "return " + CodeGeneration.firstCharUp(mmname) + "ModelCreator.getInstance();\n";
}
classbody += "default: return null;";
classbody += "}\n";
classbody += "}\n";
// getCloningMaterial
classbody += "public CloningMaterial getCloningMaterial(String metamodelName, String cloningName) {\n";
classbody += "switch (metamodelName.toLowerCase()) {\n";
for (String mmname : metamodelsnames) {
classbody += "case \"" + mmname.toLowerCase() + "\":\n";
classbody += "switch (cloningName.toLowerCase()) {\n";
for (String cloningName : cloningNames) {
imports += "import " + mmname.toLowerCase() + cloningName.toLowerCase() + "."
+ CodeGeneration.firstCharUp(mmname) + cloningName + "CloningMaterial;\n";
classbody += "case \"" + cloningName.toLowerCase() + "\":\n";
classbody += "return " + CodeGeneration.firstCharUp(mmname) + cloningName
+ "CloningMaterial.getInstance();\n";
}
classbody += "default: return null;";
classbody += "}\n";
}
classbody += "default: return null;";
classbody += "}\n";
classbody += "}\n";
// getMetrics
classbody += "public MetamodelMetrics getMetrics(String metamodelName) {\n";
classbody += "switch(metamodelName) {\n";
Iterator<ResourceSet> rsit = metamodels.iterator();
for (String mmname : metamodelsnames) {
ResourceSet metamodel = rsit.next();
classbody += "case \"" + mmname + "\": return " + computeMetrics(metamodel).toJavaConstruct() + ";\n";
}
classbody += "default: return null;\n";
classbody += "}\n";
classbody += "}\n";
// End class decl
classbody += "}\n";
// Printing everything
printer.println(CodeGeneration.formatJavaCode(header + imports + classbody));
printer.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
package fancyemfcloning.benchmark.generator;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.codegen.ecore.generator.Generator;
import org.eclipse.emf.codegen.ecore.genmodel.GenJDKLevel;
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
import org.eclipse.emf.codegen.ecore.genmodel.GenModelFactory;
import org.eclipse.emf.codegen.ecore.genmodel.generator.GenBaseGeneratorAdapter;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import fr.inria.diverse.cloning.cloner.util.EcoreHelper;
public class EMFCodeGenerator {
private static final String rootClassName = fr.inria.diverse.cloning.cloner.emfextension.impl.AbstractShareableEObject.class
.getCanonicalName();
private static final boolean overrideInterface = false;
private static final String rootInterfaceName = fr.inria.diverse.cloning.cloner.emfextension.ShareableEObject.class
.getCanonicalName();
/**
* Exception thrown when the ecore file is not valid.
*
* @author ebousse
*
*/
public static class EMFGenerationException extends Exception {
private static final long serialVersionUID = -7761342805184071165L;
String message;
public EMFGenerationException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
}
/**
* Generator operation.
*
* @param serializedMetamodel
* Ecore files that represent a metamodel.
* @param metamodelname
* The name to consider for the metamodel.
* @param project
* The Eclipse project in which the code should be generated.
* @return The loaded metamodel in memory, for further use.
* @throws EMFGenerationException
* If an ecore file is invalid.
*/
public static ResourceSet generate(Set<File> serializedMetamodel, String metamodelname, IProject project)
throws EMFGenerationException {
// First loading all the ecore files
EcoreResourceFactoryImpl fact = new EcoreResourceFactoryImpl();
if (!EPackage.Registry.INSTANCE.containsKey(EcorePackage.eNS_URI))
EPackage.Registry.INSTANCE.put(EcorePackage.eNS_URI, EcorePackage.eINSTANCE);
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("ecore", fact);
ResourceSet rs = new ResourceSetImpl();
for (File f : serializedMetamodel)
rs.getResource(URI.createFileURI(f.getAbsolutePath()), true);
// Then finding all the EPackages (we consider a single root package per ecore file)
Set<EPackage> rootPackages = new HashSet<EPackage>();
for (Resource resource : rs.getResources())
rootPackages.add((EPackage) resource.getContents().get(0));
// Analysing all EPackages
BasicDiagnostic diagnosticChain = new BasicDiagnostic();
for (EPackage ePackage : EcoreHelper.findEPackages(rs))
Diagnostician.INSTANCE.validate(ePackage, diagnosticChain);
if (diagnosticChain.getSeverity() != Diagnostic.ERROR) {
GenModel genModel = GenModelFactory.eINSTANCE.createGenModel();
genModel.setComplianceLevel(GenJDKLevel.JDK70_LITERAL);
genModel.setModelDirectory("/" + project.getName() + "/src");
for (File f : serializedMetamodel)
genModel.getForeignModel().add(new Path(f.getAbsolutePath()).lastSegment());
genModel.setModelName(metamodelname);
genModel.setRootExtendsClass(rootClassName);
if (overrideInterface)
genModel.setRootExtendsInterface(rootInterfaceName);
genModel.initialize(rootPackages);
genModel.reconcile();
genModel.setCanGenerate(true);
genModel.setValidateModel(true);
// Generating the model code from the genmodel
Generator generator = new Generator();
generator.setInput(genModel);
generator.generate(genModel, GenBaseGeneratorAdapter.MODEL_PROJECT_TYPE, "model project", new BasicMonitor());
//generator.generate(genModel, GenBaseGeneratorAdapter.MODEL_PROJECT_TYPE, "model project",null);
} else {
String message = "Couldnt generate EMF code because of an invalid ecore file. Message: ";
for (Diagnostic d : diagnosticChain.getChildren()) {
if (d.getSeverity() == Diagnostic.ERROR)
message += d.getMessage();
}
throw new EMFGenerationException(message);
}
return rs;
}
}
package fancyemfcloning.benchmark.generator;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import fancyemfcloning.benchmark.base.ModelCreator;
import fr.inria.diverse.cloning.cloner.util.EcoreHelper;
import fr.inria.diverse.cloning.materialgenerator.util.CodeGeneration;
/**
* Generator of Java source code that implements a class with a single method that creates a model of a given metamodel.
*
* @author ebousse
*
*/
public class ModelCreatorGenerator {
public static final int UNBOUNDED_MULTIPLICITY_NUMBER = 2;
/**
* Exception thrown when there are not enough model elements available for a reference with "unique"
*
* @author ebousse
*
*/
public static class NotEnoughObjectsException extends Exception {
private static final long serialVersionUID = 8314677749570934919L;
private String reference;
private String type;
public NotEnoughObjectsException(String reference, String type) {
super();
this.reference = reference;
this.type = type;
}
@Override
public String getMessage() {
return "Not enough objects to initialise reference " + reference + " of type " + type + ".\n";
}
}
/**
* The names of the objects created from each EClass
*/
private static Map<EClass, List<String>> createdObjects;
/**
* Counter used to give unique names to instances.
*/
private static int counter;
/**
* Generates a random value for a given datatype, to be printed.
*
* @param datatype
* Some Ecore datatype (not all are taken into account)
* @return THe string representation of the random value, ready to be printed.
*/
private static String generateRandomDatatypeValue(EDataType datatype) {
Random random = new Random();
switch (datatype.getName()) {
case "EInt":
return String.valueOf(random.nextInt());
case "EBoolean":
return String.valueOf(random.nextBoolean());
case "EDouble":
return String.valueOf(random.nextDouble());
case "EByte":
byte[] bytearray = new byte[1];
random.nextBytes(bytearray);
return String.valueOf(bytearray[0]);
case "EString":
return "\"" + String.valueOf(random.nextInt()) + "\"";
default:
return "-1";
}
}
/**
* Generates the line of code that will put a value in a property. Mainly here to handle the multiplicties.
*
* @param feature
* The property in which to put a value.
* @param objectName
* The object whose property is written.
* @param value
* The string representation of the value to put.
* @return The line of code doing all this.
*/
private static String createSetOrAddValue(EStructuralFeature feature, String objectName, String value) {
if (feature.isMany()) {
return objectName + ".get" + CodeGeneration.firstCharUp(feature.getName()) + "()" + ".add(" + value
+ ");\n";
} else {
return objectName + ".set" + CodeGeneration.firstCharUp(feature.getName()) + "(" + value + ");\n";
}
}
/**
* Generates a unique ID for an object.
*
* @return The unique ID.
*/
private static String generateObjectNumber() {
return String.valueOf(counter++);
}
private static String generateObjectName(EClass c) {
return c.getName().toLowerCase() + generateObjectNumber();
}
/**
* Generates the lines of code required to create an object and all its containments, including all of their
* attributes. Recursive.
*
* @param c
* The class of the object to create.
* @param objectName
* The name of the object to create.
* @return The lines of code doing all that.
*/
private static String generateObjectCreationRec(EClass c, String objectName) {
createdObjects.get(c).add(objectName);
// Creation of the object
String objectCreation = c.getName() + " " + objectName + "=factory" + c.getEPackage().getName() + ".create"
+ c.getName() + "();\n";
// Creation of the children (by containment)
String childrenCreation = "";
// For each feature
for (EStructuralFeature feature : c.getEAllStructuralFeatures()) {
// We compute the number of objects/primitives to create
int numberOfChildren = 0;
int upperBound = feature.getUpperBound();
if (upperBound <= -1)
numberOfChildren = UNBOUNDED_MULTIPLICITY_NUMBER;
else
numberOfChildren = upperBound;
// Then we create them
for (int i = 0; i < numberOfChildren; i++) {
// If attribute, random generation
if (feature instanceof EAttribute) {
EAttribute att = (EAttribute) feature;
objectCreation += createSetOrAddValue(att, objectName,
generateRandomDatatypeValue(att.getEAttributeType()));
}
// If containment, recursive call
if (feature instanceof EReference) {
EReference ref = (EReference) feature;
if (ref.isContainment()) {
String childName = generateObjectName(ref.getEReferenceType());
childrenCreation += generateObjectCreationRec(ref.getEReferenceType(), childName);
objectCreation += createSetOrAddValue(ref, objectName, childName);
}
}
}
}
// Returning the constructed string
return childrenCreation + objectCreation;
}
/**
* Generates the lines of code that will randomly initialise all the references of all the objects, considering that
* all objects already exist. Uses the field "createdObjects" to do so.
*
* @return The lines of code doing that.
* @throws NotEnoughObjectsException
* If there are not enough objects available to fill a "many" and "unique" reference
*/
private static String generateReferencesSet() throws NotEnoughObjectsException {
String out = "";
for (EClass c : createdObjects.keySet()) {
for (String objectName : createdObjects.get(c)) {
// For each reference
for (EReference ref : c.getEAllReferences()) {
if (!ref.isContainment()) {
EClass type = ref.getEReferenceType();
// We compute the number of objects to set
int numberOfChildren = 0;
int upperBound = ref.getUpperBound();
if (upperBound <= -2)
numberOfChildren = UNBOUNDED_MULTIPLICITY_NUMBER;
else
numberOfChildren = upperBound;
// Then we set them
List<String> possibleObjects = createdObjects.get(type);
if (ref.isUnique()) {
Iterator<String> it = possibleObjects.iterator();
for (int i = 0; i < numberOfChildren; i++) {
if (it.hasNext()) {
out += createSetOrAddValue(ref, objectName, it.next());
} else {
throw new NotEnoughObjectsException(c.getName() + "." + ref.getName(), ref
.getEReferenceType().getName());
}
}
} else {
for (int i = 0; i < numberOfChildren; i++) {
String object = possibleObjects.get(new Random().nextInt(possibleObjects.size()));
out += createSetOrAddValue(ref, objectName, object);