diff --git a/moclodash/fr.inria.diverse.cloning.external-libs/.classpath b/moclodash/fr.inria.diverse.cloning.external-libs/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..a6f7254100cef44362d7906a2a763ad22205b0db --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.external-libs/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.external-libs/.gitignore b/moclodash/fr.inria.diverse.cloning.external-libs/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5e56e040ec0902e58df8573adaec65c5da6e9304 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.external-libs/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/moclodash/fr.inria.diverse.cloning.external-libs/.project b/moclodash/fr.inria.diverse.cloning.external-libs/.project new file mode 100644 index 0000000000000000000000000000000000000000..40be714cc430de7a3a061cd8a207b053e7c8ad31 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.external-libs/.project @@ -0,0 +1,28 @@ + + + fr.inria.diverse.cloning.external-libs + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/moclodash/fr.inria.diverse.cloning.external-libs/.settings/org.eclipse.jdt.core.prefs b/moclodash/fr.inria.diverse.cloning.external-libs/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..f42de363afaae68bbd968318f1d331877f5514fc --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.external-libs/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/moclodash/fr.inria.diverse.cloning.external-libs/META-INF/MANIFEST.MF b/moclodash/fr.inria.diverse.cloning.external-libs/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000000000000000000000000000000..c119376212b3d8d0e1a0e1c5d3e10499f852fe49 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.external-libs/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: External-libs +Bundle-SymbolicName: fr.inria.diverse.cloning.external-libs +Bundle-Version: 0.1.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-ClassPath: ., + lib/commons-io-1.4.jar, + lib/jopt-simple-4.6.jar, + lib/slf4j-api-1.6.6.jar, + lib/slf4j-jdk14-1.6.6.jar, + lib/zt-zip-1.7.jar +Export-Package: joptsimple, + org.zeroturnaround.zip diff --git a/moclodash/fr.inria.diverse.cloning.external-libs/build.properties b/moclodash/fr.inria.diverse.cloning.external-libs/build.properties new file mode 100644 index 0000000000000000000000000000000000000000..4d92724042eaf9fdc48fa8a8ed192e4f69c44c6a --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.external-libs/build.properties @@ -0,0 +1,9 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + lib/commons-io-1.4.jar,\ + lib/jopt-simple-4.6.jar,\ + lib/slf4j-api-1.6.6.jar,\ + lib/slf4j-jdk14-1.6.6.jar,\ + lib/zt-zip-1.7.jar diff --git a/moclodash/fr.inria.diverse.cloning.external-libs/pom.xml b/moclodash/fr.inria.diverse.cloning.external-libs/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..214d19c0da28dad3b178efd489a209fa2012f208 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.external-libs/pom.xml @@ -0,0 +1,123 @@ + + + + 4.0.0 + fr.inria.diverse.cloning + fr.inria.diverse.cloning.external-libs + 0.1.0-SNAPSHOT + eclipse-plugin + + + fr.inria.diverse.cloning + moclodash + 0.1.0-SNAPSHOT + + + + + org.zeroturnaround + zt-zip + 1.7 + jar + compile + + + net.sf.jopt-simple + jopt-simple + 4.6 + jar + compile + + + org.slf4j + slf4j-jdk14 + 1.6.6 + jar + compile + + + + + + + + + + org.apache.maven.plugins + + maven-dependency-plugin + + + + copy-dependencies + + initialize + + + copy-dependencies + + + + true + + ${project.basedir}/lib + + ${project.basedir}/lib + + + + + + + org.apache.maven.plugins + + maven-clean-plugin + + + + clean-dependencies + clean + + + clean + + + + + + + lib + + + + **/* + + + + + + + + + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/.project b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/.project new file mode 100644 index 0000000000000000000000000000000000000000..aae38ee7204d2829ae5e9b1b390dded9954d2019 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/.project @@ -0,0 +1,11 @@ + + + fr.inria.diverse.cloning.materialgenerator.cli.product + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/main.product b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/main.product new file mode 100644 index 0000000000000000000000000000000000000000..8be1e142cf3f816fb302926fd445f562379d4847 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/main.product @@ -0,0 +1,34 @@ + + + + + + + + + + -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/pom.xml b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..957f58d15d4d4fce18e245ca112f5f786c8e0c3c --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli.product/pom.xml @@ -0,0 +1,48 @@ + + + + 4.0.0 + fr.inria.diverse.cloning + fr.inria.diverse.cloning.materialgenerator.cli.product + 0.1.0-SNAPSHOT + eclipse-repository + + + fr.inria.diverse.cloning + moclodash + 0.1.0-SNAPSHOT + + + + + + + + org.eclipse.tycho + tycho-p2-director-plugin + ${tycho.version} + + + create-product-distributions + + materialize-products + archive-products + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.classpath b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..098194ca4b7d8f45177f94e735506ae3a26b5c94 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.gitignore b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5e56e040ec0902e58df8573adaec65c5da6e9304 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.project b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.project new file mode 100644 index 0000000000000000000000000000000000000000..8a18f018784a0cd7d1cb25686bd04a4893c56f9a --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.project @@ -0,0 +1,28 @@ + + + fr.inria.diverse.cloning.materialgenerator.cli + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.settings/org.eclipse.jdt.core.prefs b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..f42de363afaae68bbd968318f1d331877f5514fc --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/META-INF/MANIFEST.MF b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000000000000000000000000000000..10b64dd643ab7d48be304a2da5c1138c70741895 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: App +Bundle-SymbolicName: fr.inria.diverse.cloning.materialgenerator.cli;singleton:=true +Bundle-Version: 0.1.0.qualifier +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.core.resources, + org.eclipse.jdt.core, + fr.inria.diverse.cloning.materialgenerator, + fr.inria.diverse.cloning.external-libs;bundle-version="0.1.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-ClassPath: . diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/build.properties b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/build.properties new file mode 100644 index 0000000000000000000000000000000000000000..d3ec1bc5a89e4ffd2fb31c5d8a13897fc4cbdd3f --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/build.properties @@ -0,0 +1,5 @@ +output.. = bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + . +source.. = src/ diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/plugin.xml b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/plugin.xml new file mode 100644 index 0000000000000000000000000000000000000000..e750e0b7fc67c1e39eff6de14a71ffdafc81cc0e --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/plugin.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/pom.xml b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e07cc823fbd6361048d6c4189a8b94fcd81ac8e --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/pom.xml @@ -0,0 +1,27 @@ + + + + 4.0.0 + fr.inria.diverse.cloning + fr.inria.diverse.cloning.materialgenerator.cli + 0.1.0-SNAPSHOT + eclipse-plugin + + + fr.inria.diverse.cloning + moclodash + 0.1.0-SNAPSHOT + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/src/fr/inria/diverse/cloning/materialgenerator/cli/Application.java b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/src/fr/inria/diverse/cloning/materialgenerator/cli/Application.java new file mode 100644 index 0000000000000000000000000000000000000000..e414bfd37642593bd7a86b0c43f0e8a5fa364e44 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator.cli/src/fr/inria/diverse/cloning/materialgenerator/cli/Application.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.cli; + +import java.io.File; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import joptsimple.OptionException; +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import joptsimple.OptionSpec; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Path; +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; + +import fr.inria.diverse.cloning.materialgenerator.start.Start; + +/** + * This class controls all aspects of the application's execution + */ +public class Application implements IApplication { + + /* + * + * + * (non-Javadoc) + * + * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app. IApplicationContext) + */ + public Object start(IApplicationContext context) throws Exception { + + String[] args = (String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS); + + // Specifying arguments + OptionParser parser = new OptionParser(); + + OptionSpec ecoreFilesOption = parser.accepts("ecoreFiles", "The ecore files describing the metamodel.") + .withRequiredArg().required().describedAs("path1,path2,...").ofType(File.class) + .withValuesSeparatedBy(",").required(); + + OptionSpec emfProjectFolderOption = parser + .accepts("emfProjectFolder", "The folder of the eclipse java project with generated emf code.") + .withRequiredArg().required().describedAs("path").ofType(File.class).required(); + + OptionSpec metamodelNameOption = parser.accepts("metamodelName", "The name of the metamodel.") + .withRequiredArg().required().ofType(String.class).required(); + + OptionSpec emfGenerationOption = parser.accepts("generateEMFcode", + "Whether the EMF model code should be generated, with appropriate super types for classes."); + + try { + + // Parsing arguments (throws an error if problem) + OptionSet options = parser.parse(args); + List ecoreFiles = options.valuesOf(ecoreFilesOption); + Set ecoreFilesSet = new HashSet(ecoreFiles); + File emfProjectFolder = options.valueOf(emfProjectFolderOption); + String metamodelName = options.valueOf(metamodelNameOption); + boolean emfGen = options.has(emfGenerationOption); + + // Creating a "fake" java project from a real existing eclipse java // project on the filesystem + IProjectDescription description = ResourcesPlugin.getWorkspace().loadProjectDescription( + new Path(new File(emfProjectFolder, ".project").getAbsolutePath())); + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(description.getName()); + project.delete(false, true, null); + project.create(description, null); + project.open(null); + IJavaProject javaProject = JavaCore.create(project); + + Start.start(ecoreFilesSet, metamodelName, javaProject, emfGen); + + } catch (OptionException e) { + System.out.println("Invalid options: " + e.getMessage()); + parser.printHelpOn(System.out); + } + + return IApplication.EXIT_OK; + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.equinox.app.IApplication#stop() + */ + public void stop() { + // nothing to do + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/.classpath b/moclodash/fr.inria.diverse.cloning.materialgenerator/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..db3449225d861a2829a4297e48cb62048f162ef0 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/.gitignore b/moclodash/fr.inria.diverse.cloning.materialgenerator/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5e56e040ec0902e58df8573adaec65c5da6e9304 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/.project b/moclodash/fr.inria.diverse.cloning.materialgenerator/.project new file mode 100644 index 0000000000000000000000000000000000000000..b0578112b735fbc5b1c059bef78e69bdb4560739 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/.project @@ -0,0 +1,28 @@ + + + fr.inria.diverse.cloning.materialgenerator + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/.settings/org.eclipse.core.resources.prefs b/moclodash/fr.inria.diverse.cloning.materialgenerator/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000000000000000000000000000000000..a0425b2cce0901ac32e5faeb88977be5a6234b6b --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//testdata/mm8.ecorediag=UTF-8 diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/.settings/org.eclipse.jdt.core.prefs b/moclodash/fr.inria.diverse.cloning.materialgenerator/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..7341ab1683c4f1bd2f33bbd3d102ebf032569b57 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/META-INF/MANIFEST.MF b/moclodash/fr.inria.diverse.cloning.materialgenerator/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000000000000000000000000000000..cd758ad88eba239b27559fa853853269b1c0cdc6 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/META-INF/MANIFEST.MF @@ -0,0 +1,37 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: CloningMaterialGenerator +Bundle-SymbolicName: fr.inria.diverse.cloning.materialgenerator;singleton:=true +Bundle-Version: 0.1.0.qualifier +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.gmt.modisco.java.generation;bundle-version="0.11.1", + org.eclipse.emf.common, + org.eclipse.emf.ecore;bundle-version="2.9.1", + org.eclipse.modisco.java.discoverer;bundle-version="0.11.1", + org.eclipse.modisco.infra.discovery.core;bundle-version="0.11.1", + org.eclipse.core.resources;bundle-version="3.8.101", + org.eclipse.jdt.core;bundle-version="3.9.1", + org.eclipse.equinox.registry, + org.eclipse.gmt.modisco.java;bundle-version="0.11.1", + org.eclipse.emf.ecore.xmi;bundle-version="2.9.1", + org.eclipse.gmf.runtime.emf.core;bundle-version="1.7.0", + fr.inria.diverse.cloning.runtime;bundle-version="0.1.0", + org.eclipse.emf.codegen;bundle-version="2.9.0", + org.eclipse.emf.codegen.ecore;bundle-version="2.9.1", + org.eclipse.jface.text;bundle-version="3.8.101", + org.eclipse.ui;bundle-version="3.105.0", + org.eclipse.core.variables;bundle-version="3.2.700", + org.eclipse.debug.core;bundle-version="3.8.0", + org.eclipse.jdt.launching;bundle-version="3.7.0", + org.eclipse.debug.ui;bundle-version="3.9.0", + org.eclipse.jdt.debug.ui;bundle-version="3.6.200", + org.eclipse.ui.ide;bundle-version="3.9.1", + org.eclipse.ui.console +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Export-Package: fr.inria.diverse.cloning.materialgenerator.generators, + fr.inria.diverse.cloning.materialgenerator.metrics, + fr.inria.diverse.cloning.materialgenerator.start, + fr.inria.diverse.cloning.materialgenerator.tagger, + fr.inria.diverse.cloning.materialgenerator.tagger.impl, + fr.inria.diverse.cloning.materialgenerator.util +Bundle-ClassPath: . diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/build.properties b/moclodash/fr.inria.diverse.cloning.materialgenerator/build.properties new file mode 100644 index 0000000000000000000000000000000000000000..2b0d95b6b02b49d14dbb5f6940aa13b6f13bce29 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + . diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/javamodel/javamodel.xmi b/moclodash/fr.inria.diverse.cloning.materialgenerator/javamodel/javamodel.xmi new file mode 100644 index 0000000000000000000000000000000000000000..12e29c381b857b64bb790af797c3691352b0cc2d --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/javamodel/javamodel.xmi @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/plugin.xml b/moclodash/fr.inria.diverse.cloning.materialgenerator/plugin.xml new file mode 100644 index 0000000000000000000000000000000000000000..1ba757994fbfa1f064ccccddad75efa712b532e3 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/plugin.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/pom.xml b/moclodash/fr.inria.diverse.cloning.materialgenerator/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..161720787b74798e4330c80023ef6b5b8d132d7a --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/pom.xml @@ -0,0 +1,28 @@ + + + + 4.0.0 + fr.inria.diverse.cloning + fr.inria.diverse.cloning.materialgenerator + 0.1.0-SNAPSHOT + eclipse-plugin + + + + fr.inria.diverse.cloning + moclodash + 0.1.0-SNAPSHOT + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/CloningMaterialClassGenerator.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/CloningMaterialClassGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..de9971bc8663fd3c64445358c34b5955c23b1fac --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/CloningMaterialClassGenerator.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; + +import org.eclipse.emf.ecore.resource.ResourceSet; +import fr.inria.diverse.cloning.runtime.emfextension.impl.LooseCopier; + +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.materialgenerator.util.CodeGeneration; +import fr.inria.diverse.cloning.runtime.common.CloningMaterial; +import fr.inria.diverse.cloning.runtime.common.MetamodelTags; + +public class CloningMaterialClassGenerator { + /** + * Generates a java class implementing the MetamodelTags interface, to retrieve at runtine the generate tags of the + * metamodel classes. + * + * @param pack + * The java package in which to generate the class. + * @param srcOutputFolder + * The source folder in which all the model code is located. + */ + public static void generateCloningMaterialClass(ResourceSet metamodel, String javapackagename, File outputDir, Tagger tagger) { + // Computing the class name + String className = CodeGeneration.firstCharUp(tagger.getMetamodelName() + tagger.getCloningName() + + Constants.CLONING_MATERIAL__SUFFIX); + String tagsClassName = CodeGeneration.firstCharUp(tagger.getMetamodelName() + tagger.getCloningName() + + Constants.TAGS_SUFFIX); + + try { + // Preparing the output file + //File outputDir = new File(srcOutputFolder + "/" + generateFullyQualifiedName(pack, "/")); + outputDir.mkdirs(); + File outputFile = new File(outputDir, className + ".java"); + outputFile.createNewFile(); + PrintStream printer = new PrintStream(outputFile); + + // Package header + printer.println("package " + javapackagename + ";\n"); + + String imports = ""; + + // Imports not metamodel dependent + imports += "import " + CloningMaterial.class.getCanonicalName() + ";\n"; + //imports += "import " + LooseCopier.class.getCanonicalName() + ";\n"; + imports += "import " + MetamodelTags.class.getCanonicalName() + ";\n"; + imports += "import " + LooseCopier.class.getCanonicalName() + ";\n"; + + // Class declaration + String classdef = "public class " + className + " implements " + CloningMaterial.class.getSimpleName() + + " {\n"; + + // private instance declaration + classdef += "private static " + className + " instance;\n"; + classdef += "private " + tagsClassName + " tags;\n"; + + // private constructor declaration + classdef += "private " + className + "(" + tagsClassName + " tags){" + "this.tags = tags;\n" + "};\n"; + + // getInstance method declaration + classdef += "public static " + className + " getInstance() {\n"; + classdef += "if (instance == null)\n"; + classdef += "instance = new " + className + "(new " + tagsClassName + "());\n"; + classdef += "return instance;\n"; + // end init method declaration + classdef += "}\n"; + + // getTags method declaration + classdef += "public " + MetamodelTags.class.getSimpleName() + " getTags() {\n"; + classdef += "return tags;"; + // end getTags method declarationCopier + classdef += "}\n"; + + // createLightCopier method declaration + String copierClassName = CodeGeneration.firstCharUp(tagger.getMetamodelName() + tagger.getCloningName() + + Constants.COPIER_SUFFIX); + classdef += "public " + LooseCopier.class.getSimpleName() + " createCopier() {\n"; + if (tagger.mayTagClassesPartShareable()) + classdef += "return new " + copierClassName + "();"; + else + classdef += "return new LooseCopier ();"; + // end createLightCopier method declaration + classdef += "}\n"; + + // end class declaration + classdef += "}\n"; + + // Then ultimately we put all this studd in a file + printer.println(imports); + printer.println(classdef); + printer.close(); + } catch (IOException e) { + System.err.println("Impossible to write cloning material class " + className + "!"); + e.printStackTrace(); + } + + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/Constants.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..86e2c37ba5b835c4c0788435d447b3124010e717 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/Constants.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +public class Constants { + + public static final String COPIER_SUFFIX = "Copier"; + public static final String TAGS_SUFFIX = "Tags"; + public static final String CLONING_MATERIAL__SUFFIX = "CloningMaterial"; + public static final String METRICS__SUFFIX = "Metrics"; + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/EMFCodeGenerator.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/EMFCodeGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..75fae5df8bdab65fe4ffc9aced139accbff99168 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/EMFCodeGenerator.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +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.runtime.util.EcoreHelper; + +public class EMFCodeGenerator { + + private static final String rootClassName = fr.inria.diverse.cloning.runtime.emfextension.impl.AbstractShareableEObject.class + .getCanonicalName(); + + private static final boolean overrideInterface = false; + private static final String rootInterfaceName = fr.inria.diverse.cloning.runtime.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 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 rootPackages = new HashSet(); + 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; + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/EMFImpl2PImpl.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/EMFImpl2PImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..91b090f9e8170d87cb629a49c83da1f7ae95ca8f --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/EMFImpl2PImpl.java @@ -0,0 +1,720 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +import java.io.File; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EPackage.Registry; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.util.EcoreUtil.Copier; +import org.eclipse.gmt.modisco.java.AbstractTypeDeclaration; +import org.eclipse.gmt.modisco.java.Assignment; +import org.eclipse.gmt.modisco.java.BodyDeclaration; +import org.eclipse.gmt.modisco.java.ClassDeclaration; +import org.eclipse.gmt.modisco.java.CompilationUnit; +import org.eclipse.gmt.modisco.java.ConstructorDeclaration; +import org.eclipse.gmt.modisco.java.ExpressionStatement; +import org.eclipse.gmt.modisco.java.FieldDeclaration; +import org.eclipse.gmt.modisco.java.InterfaceDeclaration; +import org.eclipse.gmt.modisco.java.MethodDeclaration; +import org.eclipse.gmt.modisco.java.MethodInvocation; +import org.eclipse.gmt.modisco.java.Model; +import org.eclipse.gmt.modisco.java.Modifier; +import org.eclipse.gmt.modisco.java.Package; +import org.eclipse.gmt.modisco.java.ReturnStatement; +import org.eclipse.gmt.modisco.java.SingleVariableAccess; +import org.eclipse.gmt.modisco.java.SingleVariableDeclaration; +import org.eclipse.gmt.modisco.java.Statement; +import org.eclipse.gmt.modisco.java.StringLiteral; +import org.eclipse.gmt.modisco.java.TypeAccess; +import org.eclipse.gmt.modisco.java.VariableDeclaration; +import org.eclipse.gmt.modisco.java.VariableDeclarationFragment; +import org.eclipse.gmt.modisco.java.VisibilityKind; +import org.eclipse.gmt.modisco.java.emf.JavaFactory; + +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.util.Log; + +public class EMFImpl2PImpl { + + /** + * MetaClasses mapping between the Java model and the Ecore model. + */ + private Map classesMapping; + + /** + * Properties mapping between the Java model and the Ecore model. + */ + private Map propertiesMapping; + + /** + * Java classes that will be used as bases in the generation process. + */ + private Set toProcess; + + /** + * All the java classes implementing metaclasses + */ + private Set wholeMetamodel; + + /** + * The model to transform + */ + private Model javaModel; + + /** + * The cloning tagger to consider. It completely drives the transformation regarding what is mutable or not. + */ + private Tagger tagger; + + private boolean readonlyWarningsInSetters; + + /** + * Retrieves from the tagger the mutability tag of a java class that implements a metaclass. + * + * @param classd + * A java class that implements a metaclass. + * @return The tag of the metaclass (telling how mutable it is) + */ + private ClassTag getTagOfClass(ClassDeclaration classd) { + return getTagOfInterface((InterfaceDeclaration) classd.getSuperInterfaces().get(0).getType()); + } + + /** + * Retrieves from the tagger the mutability tag of a java interfaces that corresponds to a metaclass. + * + * @param classd + * A java interfaces that matches a metaclass. + * @return The tag of the metaclass (telling how mutable it is) + */ + private ClassTag getTagOfInterface(InterfaceDeclaration classd) { + return tagger.getTagOfEClass(classesMapping.get(classd)); + } + + /** + * Retrieves from the tagger the mutability (mutable or not) of a java property that implements a metaclass + * property. + * + * @param vard + * The java property that implements a metaclass property. + * @return True if the metaproperty is mutable, false otherwise. + */ + private boolean isFieldShareable(VariableDeclarationFragment vard) { + return tagger.isPropertyShareable(propertiesMapping.get(vard)); + } + + /** + * To decide whether a property is mutable or not. Only relies on its name, which should end with "_m" or + * "_M_EDEFAULT" for default values. + * + * @param variable + * The variable to analyse + * @return True if mutable, false otherwise. + */ + /* + * private boolean isMutable(VariableDeclarationFragment variable) { + * + * boolean pointsToMutable = false; if (variable.getVariablesContainer() instanceof FieldDeclaration) { + * FieldDeclaration fieldd = (FieldDeclaration) variable.getVariablesContainer(); if (fieldd.getType() != null && + * fieldd.getType().getType() instanceof InterfaceDeclaration) { InterfaceDeclaration interfaced = + * (InterfaceDeclaration) fieldd.getType().getType(); ClassTag tag = getTagOfInterface(interfaced); + * + * switch (tag) { // case canReachMutable: // pointsToMutable = true; case completelyMutable: pointsToMutable = + * true; case completelyReadonly: pointsToMutable = false; case partiallyMutable: pointsToMutable = true; } + * + * } + * + * } + * + * return pointsToMutable || variable.getName().endsWith("_m") || variable.getName().endsWith("_M_EDEFAULT"); } + */ + + /** + * Helper method that allows one to find the method that contain some model element. + * + * @param o + * The model element. + * @return The method containing the model element. + */ + private static MethodDeclaration getContainingMethod(EObject o) { + if (o.eContainer() != null) { + if (o.eContainer() instanceof MethodDeclaration) + return (MethodDeclaration) o.eContainer(); + else + return getContainingMethod(o.eContainer()); + } else { + return null; + } + } + + /** + * Constructor of the transformation. Parameterized by the model to transform and the tagger used. + * + * @param javaModel + * @param tagger + */ + public EMFImpl2PImpl(Model javaModel, Tagger tagger, boolean readonlyWarningsInSetters) { + super(); + this.javaModel = javaModel; + this.tagger = tagger; + this.classesMapping = new HashMap(); + this.propertiesMapping = new HashMap(); + this.toProcess = new HashSet(); + this.wholeMetamodel = new HashSet(); + this.readonlyWarningsInSetters = readonlyWarningsInSetters; + computeMapping(); + } + + /** + * Helper method to create "System..println()" calls in the code. Creates a fake System class, a + * fake err static property, and a fake printlnt method. Then creates the call itself and return it. + * + * @param message + * The message that should be printed by the call. + * @param stream + * Either "out" or "err". + * @return The method call. + */ + private ExpressionStatement createPrint(String message, String stream) { + + // Preparing the factory + JavaFactory javaFactory = (JavaFactory) Registry.INSTANCE + .getEFactory("http://www.eclipse.org/MoDisco/Java/0.2.incubation/java"); + + // Fake "err" static field of System + FieldDeclaration errField = javaFactory.createFieldDeclaration(); + Modifier errModifier = javaFactory.createModifier(); + errModifier.setStatic(true); + errField.setModifier(errModifier); + VariableDeclarationFragment err = javaFactory.createVariableDeclarationFragment(); + err.setName(stream); + errField.getFragments().add(err); + + // Fake println method + MethodDeclaration println = javaFactory.createMethodDeclaration(); + println.setName("println"); + + // Argument for the call, which is the message + StringLiteral arg = javaFactory.createStringLiteral(); + arg.setEscapedValue("\"" + message + "\""); + + // Fake System class + ClassDeclaration system = javaFactory.createClassDeclaration(); + system.setName("System"); + system.getBodyDeclarations().add(println); + system.getBodyDeclarations().add(errField); + + // To access to the system class + TypeAccess systemAccess = javaFactory.createTypeAccess(); + systemAccess.setType(system); + + // To access to the "err" field + SingleVariableAccess erraccess = javaFactory.createSingleVariableAccess(); + erraccess.setVariable(err); + erraccess.setQualifier(systemAccess); + + // Invocation of the fake println method + MethodInvocation printlncall = javaFactory.createMethodInvocation(); + printlncall.setMethod(println); + printlncall.setExpression(erraccess); + printlncall.getArguments().add(arg); + + // Finally creating the expression result, containing the invocation of println + ExpressionStatement result = javaFactory.createExpressionStatement(); + result.setExpression(printlncall); + + // And returning it + return result; + } + + /** + * Helper method to find the getter of some property in the original model. For instance: in APImpl the attribute a + * would return the getA() method of AImpl. + * + * @param variable + * The property for which we need the original getter. + * @param copier + * The copier that produced the java model clone. + * @return + */ + private MethodDeclaration findGetterInImpl(VariableDeclarationFragment variable, EcoreUtil.Copier copier) { + + VariableDeclarationFragment realvariable = (VariableDeclarationFragment) copier.get(variable); + + for (SingleVariableAccess access : realvariable.getUsageInVariableAccess()) { + if (access.eContainer() instanceof ReturnStatement) { + ReturnStatement ret = (ReturnStatement) access.eContainer(); + if (ret.eContainer().eContainer() instanceof MethodDeclaration) { + MethodDeclaration potentialGetter = (MethodDeclaration) ret.eContainer().eContainer(); + // If found return, the getter + if (potentialGetter.getName().startsWith("get") || potentialGetter.getName().startsWith("is")) + return potentialGetter; + } + + } + } + // If not found, return null + return null; + } + + /** + * Method called on each readonly field, from the processClass body. + * + * @param variabled + * The readonly field to transform. + * @param copier + * The copier used to obtain the clone for the transformation. + * @param classd + * The java class that contains the field. + * @param clonedVar + * The field in the java regular implementation + */ + private void processShareableProperty(VariableDeclarationFragment variabled, Copier copier, ClassDeclaration classd, + VariableDeclaration clonedVar) { + + // Preparing the factory + JavaFactory javaFactory = (JavaFactory) Registry.INSTANCE + .getEFactory("http://www.eclipse.org/MoDisco/Java/0.2.incubation/java"); + + // We iterate through its usages + for (SingleVariableAccess access : variabled.getUsageInVariableAccess()) { + + // Getting the method that contains this write + MethodDeclaration containingMethod = getContainingMethod(access); + + if (containingMethod != null) { + + // case WRITE (setters) + if (containingMethod.getName().startsWith("basicSet") || containingMethod.getName().startsWith("set")) { + + // If we are, we clear its content + containingMethod.getBody().getStatements().clear(); + // and we replace it with some error printing + if (readonlyWarningsInSetters) { + ExpressionStatement printExpr = createPrint( + "[Info] " + classd.getName() + ": " + variabled.getName() + + " is readonly and cannot be set.", "out"); + printExpr.setOriginalCompilationUnit(classd.getOriginalCompilationUnit()); + containingMethod.getBody().getStatements().add(printExpr); + } + // If in a basicSet, we have to return the NotificationChain + if (containingMethod.getName().startsWith("basicSet")) { + + SingleVariableAccess parameterAccess = javaFactory.createSingleVariableAccess(); + parameterAccess.setVariable(containingMethod.getParameters().get(1)); + + ReturnStatement ret = javaFactory.createReturnStatement(); + ret.setExpression(parameterAccess); + + containingMethod.getBody().getStatements().add(ret); + + } + + } + + // case READ + else { + + if (containingMethod != null) { + + // If we are in a getter, we remove everything except the return + // (i.e. we remove everything proxy related) + // TODO check if in a return ? + if (containingMethod.getName().startsWith("basicGet") + || containingMethod.getName().startsWith("get") + || containingMethod.getName().startsWith("is")) { + EList statements = new BasicEList(); + statements.addAll(containingMethod.getBody().getStatements()); + for (Statement s : statements) + if (!(s instanceof ReturnStatement)) + containingMethod.getBody().getStatements().remove(s); + } + + MethodDeclaration getter = findGetterInImpl(variabled, copier); + + if (getter != null) { + + // Creating the access to the cloned variable + SingleVariableAccess clonedAccess = javaFactory.createSingleVariableAccess(); + clonedAccess.setVariable(clonedVar); + + // Creating the call to the getter + MethodInvocation getCall = javaFactory.createMethodInvocation(); + getCall.setMethod(getter); + getCall.setExpression(clonedAccess); + + // Two cases : contained in a collection or not + // In both, we replace the access by cloned.get + if (access.eContainmentFeature().isMany()) { + @SuppressWarnings("unchecked") + EList list = (EList) access.eContainer().eGet( + access.eContainmentFeature()); + list.set(list.indexOf(access), getCall); + } else { + access.eContainer().eSet(access.eContainmentFeature(), getCall); + } + + } + + } + + } + + } + + } + } + + /** + * Main transformation method. + * + * @param classd + * The class to process + * @param originalEclass + * @param copier + * The copier used to duplicate the java model + */ + private void processClass(ClassDeclaration classd, Copier copier) { + + String newName = classd.getName().substring(0, classd.getName().length() - 4) + tagger.getSuffix(); + + // Renaming the class + // String originalName = classd.getName(); + classd.setName(newName); + classd.getOriginalCompilationUnit().setName(classd.getName() + ".java"); + + // Preparing the factory + JavaFactory javaFactory = (JavaFactory) Registry.INSTANCE + .getEFactory("http://www.eclipse.org/MoDisco/Java/0.2.incubation/java"); + + // Creating the "cloned" field... + // Added later to the class + // Maybe we should find the type in the original model ? + + FieldDeclaration clonedField = javaFactory.createFieldDeclaration(); + + // We construct an access to the "XImpl" type + TypeAccess clonedFieldTypeaccess = javaFactory.createTypeAccess(); + InterfaceDeclaration interfaced = (InterfaceDeclaration) classd.getSuperInterfaces().get(0).getType(); + clonedFieldTypeaccess.setType(interfaced); + + VariableDeclarationFragment clonedVar = javaFactory.createVariableDeclarationFragment(); + clonedVar.setName("cloned"); + clonedVar.setExtraArrayDimensions(0); + clonedVar.setProxy(false); + clonedVar.setVariablesContainer(clonedField); + clonedVar.setOriginalCompilationUnit(classd.getOriginalCompilationUnit()); + + Modifier clonedFieldModifier = javaFactory.createModifier(); + clonedFieldModifier.setStatic(false); + clonedFieldModifier.setVisibility(VisibilityKind.PROTECTED); + + clonedField.setType(clonedFieldTypeaccess); + clonedField.setModifier(clonedFieldModifier); + + // Preparing a set of the body declarations to remove + Set emptyBodies = new HashSet(); + + // First pass: analysis and processing the fields + for (BodyDeclaration bodyd : classd.getBodyDeclarations()) { + + // If it is a field + if (bodyd instanceof FieldDeclaration) { + FieldDeclaration fieldd = (FieldDeclaration) bodyd; + + // If it is not static + if (!fieldd.getModifier().isStatic()) { + + // We prepare the set of mutable variables (to remove eventually) + Set localReadonlys = new HashSet(); + // And we iterate through the variables + for (VariableDeclarationFragment variabled : fieldd.getFragments()) { + + // If it is readonly + if (isFieldShareable(variabled)) { + processShareableProperty(variabled, copier, classd, clonedVar); + localReadonlys.add(variabled); + } + + } + // We remove from the field the readonly variables + fieldd.getFragments().removeAll(localReadonlys); + // If the field is empty, it must be removed eventually + if (fieldd.getFragments().isEmpty()) + emptyBodies.add(fieldd); + + } + } + // Changing constructor + if (bodyd instanceof ConstructorDeclaration) { + ConstructorDeclaration constructor = (ConstructorDeclaration) bodyd; + + // Changing the name of the constructor + constructor.setName(newName); + + // Adding a parameter "cloned" + TypeAccess typeaccess = javaFactory.createTypeAccess(); + typeaccess.setType(interfaced); + SingleVariableDeclaration vard = javaFactory.createSingleVariableDeclaration(); + vard.setType(typeaccess); + vard.setName("clonedParam"); + constructor.getParameters().add(vard); + + // Adding a set of the "cloned" field + SingleVariableAccess clonedFieldAccess = javaFactory.createSingleVariableAccess(); + clonedFieldAccess.setVariable(clonedVar); + SingleVariableAccess clonedParamAccess = javaFactory.createSingleVariableAccess(); + clonedParamAccess.setVariable(vard); + Assignment assignment = javaFactory.createAssignment(); + assignment.setLeftHandSide(clonedFieldAccess); + assignment.setRightHandSide(clonedParamAccess); + ExpressionStatement assignStatement = javaFactory.createExpressionStatement(); + assignStatement.setExpression(assignment); + constructor.getBody().getStatements().add(assignStatement); + + } + } + + // We remove empty fields + classd.getBodyDeclarations().removeAll(emptyBodies); + + // Adding cloned field, at last (otherwise it is treated as a RO + // variable etc.) + classd.getBodyDeclarations().add(0, clonedField); + + } + + /** + * Main operation. + * + * @param srcOutputFolder + * @param originalJavaModel + * Already processed + * @return The original model /!\ + */ + public Model transform2PImpl(String srcOutputFolder) { + + // First we make a copy, because we will have to make references to original classes + EcoreUtil.Copier copier = new EcoreUtil.Copier(); + // Model originalModel = (Model) copier.copy(javaModel); + Model originalModel = (Model) copier.copy(javaModel); + copier.copyReferences(); + + // Preparing the set of compilation units to keep (ie. those modified) + Set cuToKeep = new HashSet(); + + // Creating metamodel package + JavaFactory javaFactory = (JavaFactory) Registry.INSTANCE + .getEFactory("http://www.eclipse.org/MoDisco/Java/0.2.incubation/java"); + Package pack = javaFactory.createPackage(); + pack.setName(tagger.getMetamodelName().toLowerCase() + tagger.getCloningName().toLowerCase()); + javaModel.getOwnedElements().add(pack); + + // We process each class to process (determined by the preprocessing + Log.info("Computed java classes:"); + Log.plusLevel(); + for (ClassDeclaration classd : toProcess) { + + ClassTag tag = getTagOfClass(classd); + + if (tag == ClassTag.PARTIALLY_SHAREABLE) { + + processClass(classd, copier); + + Log.info("Computed " + classd.getName() + "."); + cuToKeep.add(classd.getOriginalCompilationUnit()); + + } + + } + Log.minusLevel(); + + + File outputDir = new File(srcOutputFolder + "/" + generateFullyQualifiedName(pack, "/")); + + // Generating the copier + if (tagger.mayTagClassesPartShareable()) + LightCopierGenerator.generate(tagger.getMetamodel(),generateFullyQualifiedName(pack), outputDir, tagger); + + //generateCopierClass(tagger.getMetamodel(),generateFullyQualifiedName(pack), outputDir, tagger); + + TagsGenerator.generateTagsClass(tagger.getMetamodel(),generateFullyQualifiedName(pack), outputDir, tagger); + + //generateTagsClass(pack, srcOutputFolder); + + CloningMaterialClassGenerator.generateCloningMaterialClass(tagger.getMetamodel(),generateFullyQualifiedName(pack), outputDir, tagger); + + //generateCloningMaterialClass(pack, srcOutputFolder); + + for (ClassDeclaration classd : toProcess) { + // Then we put it in the target package + pack.getOwnedElements().add(classd); + classd.setPackage(pack); + classd.getOriginalCompilationUnit().setPackage(pack); + } + + // Keeping only compilation units that have been written, to only serialize them + javaModel.getCompilationUnits().retainAll(cuToKeep); + + // returns the model (useless ? getter better ?) + return originalModel; + } + + /** + * Generates the fully qualified name of a package, with a specific separator between packages. Useful to construct + * a path. + * + * @param pack + * The java package. + * @param separator + * The separator, e.g. "/" or "." + * @return The fully qualified name of the package, using the given separator. + */ + private String generateFullyQualifiedName(Package pack, String separator) { + if (pack.getPackage() != null) + return generateFullyQualifiedName(pack.getPackage(), separator) + separator + pack.getName(); + else + return pack.getName(); + } + + /** + * Generates the java fully qualified name of a pack, using the separator "." + * + * @param pack + * The java package. + * @return The fully qualified name of the package, using the separator "." + */ + private String generateFullyQualifiedName(Package pack) { + return generateFullyQualifiedName(pack, "."); + } + + /*private String generateFullyQualifiedName(InterfaceDeclaration interf) { + return generateFullyQualifiedName(interf.getPackage()) + "." + interf.getName(); + }*/ + + + /** + * Creates the mapping from the javamodel to the ecore model + */ + private void computeMapping() { + // We navigate through the tagger's metamodel + for (Resource ecoreResource : tagger.getMetamodel().getResources()) { + // For each package + for (EObject object : ecoreResource.getContents()) { + if (object instanceof EPackage) { + EPackage originalPackage = (EPackage) object; + // We find the corresponding java one + for (Package javaPackage : javaModel.getOwnedElements()) { + // If same name, then process + if (javaPackage.getName().equals(originalPackage.getName())) + computeMappingPackagedRec(javaPackage, originalPackage); + } + + } + + } + } + + } + + /** + * Recursive operation to create the mapping between two packages + * + * @param javaPackage + * @param originalPackage + */ + private void computeMappingPackagedRec(Package javaPackage, EPackage originalPackage) { + // Before all we find the impl package in the java package + Package impl = null; + for (Package javaSubP : javaPackage.getOwnedPackages()) { + if (javaSubP.getName().equals("impl")) { + impl = javaSubP; + break; + } + } + + // For each eclass of the original package + for (EClassifier classifier : originalPackage.getEClassifiers()) { + if (classifier instanceof EClass) { + EClass eclass = (EClass) classifier; + // We search the java implementation and we store in the map + for (AbstractTypeDeclaration typed : impl.getOwnedElements()) { + if (typed instanceof ClassDeclaration && typed.getName().equals((eclass.getName() + "Impl"))) { + ClassDeclaration classd = (ClassDeclaration) typed; + classesMapping.put((InterfaceDeclaration) classd.getSuperInterfaces().get(0).getType(), eclass); + wholeMetamodel.add(classd); + ClassTag tag = getTagOfClass(classd); + if (tag == ClassTag.PARTIALLY_SHAREABLE) { + toProcess.add(classd); + } + computeMappingInClass(classd, eclass); + break; + } + } + + } + } + + // Then for each subpackage in the original metamodel package + for (EPackage subP : originalPackage.getESubpackages()) { + // We look for the corresponding java one + for (Package javaSubP : javaPackage.getOwnedPackages()) { + if (javaSubP.getName().equals(subP.getName())) { + // And we recursively process the package + computeMappingPackagedRec(javaSubP, subP); + } + } + } + } + + /** + * Creates the mapping between the properties of a java class and its ecore metaclass. + * + * @param javaClass + * The java class. + * @param originalClass + * The ecore class. + */ + private void computeMappingInClass(ClassDeclaration javaClass, EClass originalClass) { + for (EStructuralFeature prop : originalClass.getEAllStructuralFeatures()) { + for (BodyDeclaration bodyd : javaClass.getBodyDeclarations()) { + // If it is a field + if (bodyd instanceof FieldDeclaration) { + FieldDeclaration fieldd = (FieldDeclaration) bodyd; + // If it is not static + if (!fieldd.getModifier().isStatic()) { + // And we iterate through the variables + for (VariableDeclarationFragment variabled : fieldd.getFragments()) { + // If same name, then mapping + if (variabled.getName().toLowerCase().equals(prop.getName().toLowerCase())) { + propertiesMapping.put(variabled, prop); + break; + } + } + } + } + } + } + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/LightCopierGenerator.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/LightCopierGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..33512d5f01c8f529fc99affe0e9eea8375be3e74 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/LightCopierGenerator.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Set; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.emfextension.impl.LooseCopier; +import fr.inria.diverse.cloning.runtime.util.EcoreHelper; + +public class LightCopierGenerator { + + /** + * Generates a Copier that can create light clones. + * + * @param pack + * The package in which all partial implementations are put. + * @param srcOutputFolder + * The folder in which the clas must be written. + */ + public static void generate(ResourceSet metamodel, String javapackagename, File outputDir, Tagger tagger) { + + // Computing the class name + String className = tagger.getMetamodelName() + tagger.getCloningName() + Constants.COPIER_SUFFIX; + className = Character.toUpperCase(className.charAt(0)) + className.substring(1); + + try { + // Preparing the output file + // File outputDir = new File(srcOutputFolder + "/" + generateFullyQualifiedName(pack, "/"));*/ + + outputDir.mkdirs(); + File outputFile = new File(outputDir, className + ".java"); + outputFile.createNewFile(); + PrintStream printer = new PrintStream(outputFile); + + // Package header + printer.println("package " + javapackagename + ";\n"); + + // Imports not metamodel dependent + String imports = "import org.eclipse.emf.ecore.EObject;\n"; + imports += "import " + LooseCopier.class.getCanonicalName() + ";\n"; + + // Class declaration + String classdef = "@SuppressWarnings(\"serial\")\n"; + classdef += "public class " + className + " extends " + LooseCopier.class.getSimpleName() + " {\n"; + + // Method declaration + // classdef += "@Override\n"; + classdef += "protected EObject createCopy(EObject eObject) {\n"; + + // For each class + boolean firstIf = true; + boolean hasShareable = false; + Set eClasses = EcoreHelper.findEClasses(metamodel); + for (EClass c : eClasses) { + + if (tagger.getTagOfEClass(c) == ClassTag.PARTIALLY_SHAREABLE) { + hasShareable = true; + imports += "import " + EcoreHelper.computeFullyQualifiedName(c) + ";\n"; + + // We generate its if/elseif lines + if (!firstIf) { + classdef += "else\n"; + firstIf = false; + } + classdef += "if (eObject instanceof " + c.getName() + ")\n"; + classdef += "return new " + c.getName() + tagger.getSuffix() + "((" + c.getName() + ")" + + "eObject);\n"; + + } + + else if (tagger.getTagOfEClass(c) == ClassTag.COMPLETELY_SHAREABLE) { + hasShareable = true; + imports += "import " + EcoreHelper.computeFullyQualifiedName(c) + ";\n"; + + // We generate its if/elseif lines + if (!firstIf) { + classdef += "else\n"; + firstIf = false; + } + classdef += "if (eObject instanceof " + c.getName() + ")\n"; + classdef += "return eObject;\n"; + + } + + + } + + // Default case: call to the super method + if (hasShareable) { + classdef += "else\n"; + } + + classdef += "return super.createCopy(eObject);\n"; + + // end method declaration + classdef += "}\n"; + // end class declaration + classdef += "}\n"; + + // Then ultimately we put all this stuff in a file + printer.println(imports); + printer.println(classdef); + printer.close(); + } catch (IOException e) { + System.err.println("Impossible to write copier " + className + "!"); + e.printStackTrace(); + } + + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/ManifestEditor.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/ManifestEditor.java new file mode 100644 index 0000000000000000000000000000000000000000..821f1381fed05812f977415c243f7d249c2a2c6c --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/ManifestEditor.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.jar.Attributes.Name; +import java.util.jar.Manifest; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; + +/***************************************************************************** + * Copyright (c) 2011 CEA LIST. + * + * 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: Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + * + * + * from http://dev.eclipse.org/svnroot/modeling/org.eclipse.mdt.papyrus/branches/0.8.X-EYY/plugins/configurationTK/org. + * eclipse.papyrus.customization/src/org/eclipse/papyrus/customization/plugin/ManifestEditor.java + * + *****************************************************************************/ +public class ManifestEditor { + + private IProject project; + + private IFile manifestFile; + + private Manifest manifest; + + public ManifestEditor(IProject project) throws IOException, CoreException { + this.project = project; + manifestFile = getManifestFile(); + + manifest = new Manifest(manifestFile.getContents()); + } + + public void addDependency(String dependency) { + addDependency(dependency, null); + } + + public void addDependency(String dependency, String version) { + Name rqBundle = new Name("Require-Bundle"); //$NON-NLS-1$ + String requireBundle = manifest.getMainAttributes().getValue(rqBundle); + + // TODO : Improve the detection of existing dependency + // If a.b.c exists, then a.b cannot be added (Because it is already contained) + // Moreover, the Manifest allows newlines anywhere (Including in the + // middle of a word) : check if these newlines appear in this map, + // or if they have already been parsed. If the manifest value is copied as-is in the map, + // then we need to take care of newlines when parsing it + + if (requireBundle == null) { + requireBundle = dependency; + if (version != null) { + requireBundle += ";" + version; //$NON-NLS-1$ + } + } else if (!requireBundle.contains(dependency)) { + requireBundle += "," + dependency; //$NON-NLS-1$ + if (version != null) { + requireBundle += ";" + version; //$NON-NLS-1$ + } + } + + manifest.getMainAttributes().put(rqBundle, requireBundle); + } + + public void setValue(String key, String value) { + setValue(key, "", value); //$NON-NLS-1$ + } + + public void setSingleton(boolean singleton) { + String value = manifest.getMainAttributes().getValue("bundle-symbolicName"); + String[] directives = value.split(";"); + + if (directives.length == 0) { + return; // This should not happen if the Manifest is well-formed + } else { + value = directives[0]; + boolean isDefined = false; + for (int i = 1; i < directives.length; i++) { + String directive = directives[i]; + if (directive.startsWith("singleton:=")) { + directive = "singleton:=" + singleton; + isDefined = true; + } + value += ";" + directive; + } + if (!isDefined) { + value += ";singleton:=" + singleton; + } + } + + manifest.getMainAttributes().putValue("bundle-symbolicName", value); + } + + public void setValue(String key, String name, String value) { + manifest.getAttributes(key).put(name, value); + } + + public void removeValue(String key, String value) { + + } + + public void removeValue(String key) { + manifest.getAttributes(key).remove(key); + } + + private IFile getManifestFile() { + IFile manifest = project.getFile("META-INF/MANIFEST.MF"); //$NON-NLS-1$ + if (manifest.exists()) { + return manifest; + } + + // TODO : Manifest creation not supported + return null; + } + + public void save() throws IOException, CoreException { + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + manifest.write(os); + + final StringReader reader = new StringReader(os.toString("UTF-8")); //$NON-NLS-1$ + manifestFile.setContents(new InputStream() { + + @Override + public int read() throws IOException { + return reader.read(); + } + }, true, true, null); + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/PImplGenerator.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/PImplGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..015877d6f805f03a5449aef14f28958844e34cf4 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/PImplGenerator.java @@ -0,0 +1,220 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Set; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.gmt.modisco.java.Model; +import org.eclipse.gmt.modisco.java.generation.files.GenerateJavaExtended; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.modisco.infra.discovery.core.exception.DiscoveryException; +import org.eclipse.modisco.java.discoverer.DiscoverJavaModelFromJavaProject; + +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.runtime.util.Log; + +public class PImplGenerator { + + //private static final String FAKE_PROJECT_NAME = "fakeProject"; + + /*public static void generate(Set serializedMetamodel, String metamodelname, File outputFolder, Tagger tagger, boolean readonlyWarningsInSetters) { + try { + // Creating a fake eclipse project in which the code will be generated + File tmpDir = File.createTempFile(FAKE_PROJECT_NAME, ""); + tmpDir.delete(); + tmpDir.mkdir(); + IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(FAKE_PROJECT_NAME); + description.setLocationURI(java.net.URI.create(tmpDir.getAbsolutePath())); + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(description.getName()); + project.delete(true, true, null); + project.create(description, null); + project.open(null); + + project.delete(false, true, null); + project.create(description, null); + + generate(serializedMetamodel, metamodelname, project, tagger, readonlyWarningsInSetters); + + // Copying everything from the fake project folder in the output folder + outputFolder.mkdirs(); + Copy.copyRecursive(tmpDir.toPath(), outputFolder.toPath()); + + } catch (CoreException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (IOException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } + + }*/ + + public static void generate(String metamodelname, IProject emfProject, Tagger tagger, + boolean readonlyWarningsInSetters) { + + + try { + emfProject.open(null); + + IJavaProject javaProject = JavaCore.create(emfProject); + + // Discovering the model from the project + DiscoverJavaModelFromJavaProject discoverer = new DiscoverJavaModelFromJavaProject(); + discoverer.discoverElement(javaProject, new NullProgressMonitor()); + + // Accessing the obtained model + Resource result = discoverer.getTargetModel(); + Model javaModel = (Model) result.getContents().get(0); + + // Preparing outputdir for code generation + File projectFolder = new File(emfProject.getRawLocationURI().toString()); + File outputSrc = new File(projectFolder, "src"); + outputSrc.mkdirs(); + + // Calling the partial implementations transformer with one tagger + Model originalModel = javaModel; + + originalModel = new EMFImpl2PImpl(originalModel, tagger, readonlyWarningsInSetters).transform2PImpl(outputSrc.getAbsolutePath()); + + + // Generating the code from the obtained model + GenerateJavaExtended javaGenerator = new GenerateJavaExtended(javaModel, outputSrc, new ArrayList()); + javaGenerator.doGenerate(null); + + // Generating the code from the obtained model + GenerateJavaExtended javaGenerator2 = new GenerateJavaExtended(originalModel, outputSrc, + new ArrayList()); + javaGenerator2.doGenerate(null); + + // Refreshing, in order for the project to detect the new files + emfProject.refreshLocal(IResource.DEPTH_INFINITE, null); + + // Done + System.out.println("Done!"); + + } catch (CoreException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (DiscoveryException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (IOException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } + + } + + + public static void generate(String metamodelname, IProject emfProject, Set taggers, + boolean readonlyWarningsInSetters) { + + Log.info("Starting PImpl generation."); + Log.plusLevel(); + + + try { + emfProject.open(null); + + IJavaProject javaProject = JavaCore.create(emfProject); + + // Discovering the model from the project + Log.info("Extracting model from existing EMF code."); + DiscoverJavaModelFromJavaProject discoverer = new DiscoverJavaModelFromJavaProject(); + discoverer.discoverElement(javaProject, new NullProgressMonitor()); + + // Accessing the obtained model + Resource result = discoverer.getTargetModel(); + Model javaModel = (Model) result.getContents().get(0); + + // Preparing outputdir for code generation + + File projectFolder = new File(emfProject.getRawLocationURI().toString()); + File outputSrc = new File(projectFolder, "src"); + Log.info("Preparing output folder: "+outputSrc.getAbsolutePath()); + outputSrc.mkdirs(); + + // Generating the code from the obtained model + + //GenerateJavaExtended javaGenerator = new GenerateJavaExtended(javaModel, outputSrc, new ArrayList()); + //javaGenerator.doGenerate(null); + + // Calling the partial implementations transformer with one tagger + + + Model transformedModel = javaModel; + for (Tagger tagger : taggers) { + Log.info("Generating code for tagger "+tagger.getSuffix()); + Log.plusLevel(); + Log.info("Applying transformation..."); + + // We get the original model in output... + Model originalModel = new EMFImpl2PImpl(transformedModel, tagger, readonlyWarningsInSetters).transform2PImpl(outputSrc.getAbsolutePath()); + + // Generating the code from the obtained model + Log.info("Generating code..."); + GenerateJavaExtended javaGenerator = new GenerateJavaExtended(transformedModel, outputSrc, + new ArrayList()); + javaGenerator.doGenerate(null); + + // Reseting to the original model + transformedModel = originalModel; + + Log.minusLevel(); + } + + + // Refreshing, in order for the project to detect the new files + emfProject.refreshLocal(IResource.DEPTH_INFINITE, null); + + // Done + Log.minusLevel(); + Log.info("PImpl generation done."); + + } catch (CoreException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (DiscoveryException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (IOException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } + + } + + /*public static void generate(Set serializedMetamodel, String metamodelname, IProject emfProject, Tagger tagger, boolean readonlyWarningsInSetters) { + + // Loading the ecore files in a resource set (= considered metamodel) + 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); + + generate(serializedMetamodel, rs, metamodelname, emfProject, tagger, readonlyWarningsInSetters); + + }*/ + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/TagsGenerator.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/TagsGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..1367e01b007db2b80542209e8f96e29fbc1e0828 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/generators/TagsGenerator.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.generators; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Set; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.materialgenerator.metrics.CloningMetrics; +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.materialgenerator.util.CodeGeneration; +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.common.MetamodelTags; +import fr.inria.diverse.cloning.runtime.util.EcoreHelper; + +public class TagsGenerator { + + /** + * Generates a java class implementing the MetamodelTags interface, to retrieve at runtine the generate tags of the + * metamodel classes. + * + * @param pack + * The java package in which to generate the class. + * @param srcOutputFolder + * The source folder in which all the model code is located. + */ + /** + * @param metamodel + * @param javapackagename + * @param outputDir + * @param tagger + */ + public static void generateTagsClass(ResourceSet metamodel, String javapackagename, File outputDir, Tagger tagger) { + // Computing the class name + String className = CodeGeneration.firstCharUp(tagger.getMetamodelName() + tagger.getCloningName() + + Constants.TAGS_SUFFIX); + + try { + // Preparing the output file + outputDir.mkdirs(); + File outputFile = new File(outputDir, className + ".java"); + outputFile.createNewFile(); + PrintStream printer = new PrintStream(outputFile); + + // Package header + printer.println("package " + javapackagename + ";\n"); + + // Imports not metamodel dependent + String imports = "import " + EClass.class.getCanonicalName() + ";\n"; + imports += "import " + ClassTag.class.getCanonicalName() + ";\n"; + imports += "import " + MetamodelTags.class.getCanonicalName() + ";\n"; + imports += "import " + EStructuralFeature.class.getCanonicalName() + ";\n"; + + // Class declaration + String classdef = "public class " + className + " implements " + MetamodelTags.class.getSimpleName() + + " {\n"; + + // getTagOf method declaration + classdef += "public " + ClassTag.class.getSimpleName() + " getTagOf(EClass eClass) {\n"; + + // For each class that led to a pimpl + boolean firstIf = true; + Set eClasses = EcoreHelper.findEClasses(metamodel); + for (EClass c : eClasses) { + + imports += "import " + EcoreHelper.computeFullyQualifiedName(c) + ";\n"; + + // We generate its if/elseif lines + if (!firstIf) { + classdef += "else\n"; + firstIf = false; + } + + String packageInterfaceName = EcoreHelper.computeFullyQualifiedName(c.getEPackage()) + "." + + CodeGeneration.firstCharUp(c.getEPackage().getName()) + "Package"; + + classdef += "if (eClass.equals(" + packageInterfaceName + ".eINSTANCE.get" + c.getName() + "()))\n"; + classdef += "return " + ClassTag.class.getSimpleName() + "." + tagger.getTagOfEClass(c) + ";\n"; + + } + + // Default case: call to the super method + classdef += "else\n"; + classdef += "return null;\n"; + + // end getTagOf method declaration + classdef += "}\n"; + + // mayTagClassesReadonly method declaration + // classdef += "@Override\n"; + classdef += "public boolean mayTagClassesShareable() {\n"; + classdef += "return " + tagger.mayTagClassesShareable() + ";"; + + // end mayTagClassesReadonly method declaration + classdef += "}\n"; + + // isPropertyMutable method declaration + classdef += "public boolean isPropertyShareable(EStructuralFeature prop) {\n"; + + // For each class that led to a pimpl + boolean firstIf2 = true; + for (EClass c : eClasses) { + + for (EStructuralFeature prop : c.getEStructuralFeatures()) { + + // We generate its if/elseif lines + if (!firstIf2) { + classdef += "else\n"; + firstIf2 = false; + } + + String packageInterfaceName = EcoreHelper.computeFullyQualifiedName(c.getEPackage()) + "." + + CodeGeneration.firstCharUp(c.getEPackage().getName()) + "Package"; + + classdef += "if (prop.equals(" + packageInterfaceName + ".eINSTANCE.get" + c.getName() + "_" + + CodeGeneration.firstCharUp(prop.getName()) + "()))\n"; + classdef += "return " + String.valueOf(tagger.isPropertyShareable(prop)) + ";\n"; + + } + } + // Default case + classdef += "else\n"; + classdef += "return false;\n"; + + // end isPropertyMutable method declaration + classdef += "}\n"; + + + // metrics methods declaration + classdef += "public double getShareableClassesRatio() {\n"; + classdef += "return " + CloningMetrics.computeShareableClassesRatio(metamodel, tagger) + ";\n"; + classdef += "}\n"; + classdef += "public double getPartShareableClassesRatio() {\n"; + classdef += "return " + CloningMetrics.computePartShareableClassesRatio(metamodel, tagger) + ";\n"; + classdef += "}\n"; + classdef += "public double getIsolatedShareablePropertiesRatio() {\n"; + classdef += "return " + CloningMetrics.computeIsolatedShareablePropertiesRatio(metamodel, tagger) + ";\n"; + classdef += "}\n"; + classdef += "public double getShareablePropertiesInPartShareableClassesDensity() {\n"; + classdef += "return " + CloningMetrics.computeShareablePropertiesInPartShareableClassesDensity(metamodel, tagger)+ ";\n"; + classdef += "}\n"; + classdef += "public double getShareablePropertiesInShareableClassesDensity() {\n"; + classdef += "return " + CloningMetrics.computeShareablePropertiesInShareableClassesDensity(metamodel, tagger)+ ";\n"; + classdef += "}\n"; + // end metrics methods declaration + + // end class declaration + classdef += "}\n"; + + // Then ultimately we put all this studd in a file + printer.println(imports); + printer.println(classdef); + printer.close(); + } catch (IOException e) { + System.err.println("Impossible to write tags " + className + "!"); + e.printStackTrace(); + } + + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/metrics/CloningMetrics.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/metrics/CloningMetrics.java new file mode 100644 index 0000000000000000000000000000000000000000..51f3b0b70c79e49ec3839bb40882131d44524cae --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/metrics/CloningMetrics.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.metrics; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.util.EcoreHelper; + +public class CloningMetrics { + + public static double computeShareableClassesRatio(ResourceSet metamodel, Tagger tagger) { + double numberOfClasses = 0; + double numberOfCompletelyShareableClasses = 0; + for (EClass c : EcoreHelper.findEClasses(metamodel)) { + numberOfClasses++; + ClassTag tag = tagger.getTagOfEClass(c); + if (tag == ClassTag.COMPLETELY_SHAREABLE) + numberOfCompletelyShareableClasses++; + } + return numberOfCompletelyShareableClasses / numberOfClasses; + } + + public static double computePartShareableClassesRatio(ResourceSet metamodel, Tagger tagger) { + double numberOfClasses = 0; + double numberOfPartShareableClasses = 0; + for (EClass c : EcoreHelper.findEClasses(metamodel)) { + numberOfClasses++; + ClassTag tag = tagger.getTagOfEClass(c); + if (tag == ClassTag.PARTIALLY_SHAREABLE) + numberOfPartShareableClasses++; + } + return numberOfPartShareableClasses / numberOfClasses; + } + + // public static double computeShareableAttributesRatio(ResourceSet metamodel, Tagger tagger) { + // double numberOfProperties = 0; + // double numberOfShareableProperties = 0; + // for (EClass c : EcoreHelper.findEClasses(metamodel)) { + // for (EStructuralFeature prop : c.getEStructuralFeatures()) { + // numberOfProperties++; + // if (prop instanceof EAttribute) { + // boolean tag = tagger.isPropertyShareable(prop); + // if (tag) + // numberOfShareableProperties++; + // } + // } + // } + // return numberOfShareableProperties / numberOfProperties; + // } + + // the higher, the better for sharing properties (not that sure) + public static double computeIsolatedShareablePropertiesRatio(ResourceSet metamodel, Tagger tagger) { + double numberOfProperties = 0; + double numberOfShareableProperties = 0; + for (EClass c : EcoreHelper.findEClasses(metamodel)) { + for (EStructuralFeature prop : c.getEStructuralFeatures()) { + numberOfProperties++; + if (tagger.getTagOfEClass(c) == ClassTag.PARTIALLY_SHAREABLE) { + //if (prop instanceof EAttribute) { + boolean tag = tagger.isPropertyShareable(prop); + if (tag) + numberOfShareableProperties++; + //} + } + } + } + return numberOfShareableProperties / numberOfProperties; + } + + // the higher, the better for sharing properties + public static double computeShareablePropertiesInPartShareableClassesDensity(ResourceSet metamodel, Tagger tagger) { + double numberOfClasses = 0; + double numberOfShareableProperties = 0; + for (EClass c : EcoreHelper.findEClasses(metamodel)) { + if (tagger.getTagOfEClass(c) == ClassTag.PARTIALLY_SHAREABLE) { + numberOfClasses++; + for (EStructuralFeature prop : c.getEStructuralFeatures()) { + //if (prop instanceof EAttribute) { + boolean tag = tagger.isPropertyShareable(prop); + if (tag) + numberOfShareableProperties++; + //} + } + } + } + if (numberOfClasses == 0) + return 0; + else + return numberOfShareableProperties / numberOfClasses; + } + + // the higher, the better for sharing properties + public static double computeShareablePropertiesInShareableClassesDensity(ResourceSet metamodel, Tagger tagger) { + double numberOfClasses = 0; + double numberOfShareableProperties = 0; + for (EClass c : EcoreHelper.findEClasses(metamodel)) { + if (tagger.getTagOfEClass(c) == ClassTag.COMPLETELY_SHAREABLE) { + numberOfClasses++; + for (EStructuralFeature prop : c.getEStructuralFeatures()) { + //if (prop instanceof EAttribute) { + boolean tag = tagger.isPropertyShareable(prop); + if (tag) + numberOfShareableProperties++; + //} + } + } + } + if (numberOfClasses == 0) + return 0; + else + return numberOfShareableProperties / numberOfClasses; + } + + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/Activator.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/Activator.java new file mode 100644 index 0000000000000000000000000000000000000000..621c3b6dd48be45c232a777e19e3e2a7dd82aa89 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/Activator.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.plugin; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "APlugin"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunch.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunch.java new file mode 100644 index 0000000000000000000000000000000000000000..24e9ff3ce1d6964e9b3db0d55a6db0695ee1c72b --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunch.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.plugin; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate; + +import fr.inria.diverse.cloning.materialgenerator.start.Start; +import fr.inria.diverse.cloning.runtime.util.Log; + +public class CloningMaterialGenerationLaunch extends AbstractJavaLaunchConfigurationDelegate { + + @Override + public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) + throws CoreException { + // TODO Stub de la méthode généré automatiquement + + String mmName = configuration.getAttribute("mmName", ""); + boolean emf = configuration.getAttribute("emf", false); + IJavaProject project = getJavaProject(configuration); + File ecoreFolder = getWorkingDirectory(configuration); + + List files = Arrays.asList((ecoreFolder.listFiles(new EcoreFileFilter()))); + Set filesSet = new HashSet(files); + + Log.enableEclipseConsole("Cloning material generator console."); + Start.start(filesSet, mmName, project, emf); + + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunchTab.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunchTab.java new file mode 100644 index 0000000000000000000000000000000000000000..cc78f5e4bca1b104dd226f38b15bb05eafa664cd --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunchTab.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.plugin; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.variables.VariablesPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.internal.ui.DebugUIPlugin; +import org.eclipse.debug.internal.ui.SWTFactory; +import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsMessages; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.StringVariableSelectionDialog; +import org.eclipse.jdt.internal.debug.ui.IJavaDebugHelpContextIds; +import org.eclipse.jdt.internal.debug.ui.launcher.AbstractJavaMainTab; +import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.swt.SWT; +import org.eclipse.swt.accessibility.AccessibleAdapter; +import org.eclipse.swt.accessibility.AccessibleEvent; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.dialogs.ContainerSelectionDialog; +import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; +import org.eclipse.ui.model.WorkbenchContentProvider; +import org.eclipse.ui.model.WorkbenchLabelProvider; +import org.eclipse.ui.views.navigator.ResourceComparator; + +@SuppressWarnings("restriction") +public class CloningMaterialGenerationLaunchTab extends AbstractJavaMainTab { + + // Local/shared UI widgets + private Button fEcoreFolderBrowse; + private Text fEcoreFolderText; + private Button fVariables; + private Button fWorkspaceBrowse; + private Text fMetamodelNameText; + private Button fEMFCheckButton; + + private void createEMFCheckbox(Composite parent) { + fEMFCheckButton = SWTFactory.createCheckButton(parent, "Generate EMF model code with appropriate supertypes.", + null, false, 1); + fEMFCheckButton.addSelectionListener(getDefaultListener()); + } + + @Override + public void createControl(Composite parent) { + Composite comp = SWTFactory.createComposite(parent, parent.getFont(), 1, 1, GridData.FILL_BOTH); + ((GridLayout) comp.getLayout()).verticalSpacing = 0; + createEcoreFolderComponent(comp); + createVerticalSpacer(comp, 1); + createProjectEditor(comp); + ((Group) fProjText.getParent()).setText("Plug-in/EMF project with EMF model code of the metamodel."); + createVerticalSpacer(comp, 1); + createMetamodelNameComponent(comp); + createEMFCheckbox(comp); + setControl(comp); + PlatformUI.getWorkbench().getHelpSystem() + .setHelp(getControl(), IJavaDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_MAIN_TAB); + } + + /** + * Modify listener that simply updates the owning launch configuration dialog. + */ + private ModifyListener fBasicModifyListener = new ModifyListener() { + public void modifyText(ModifyEvent evt) { + scheduleUpdateJob(); + } + }; + + /** + * Constant representing the id of the {@link IDialogSettings} location for the {@link ContainerSelectionDialog} + * used on this tab + * + * @since 3.6 + */ + private final String WORKSPACE_SELECTION_DIALOG = IDebugUIConstants.PLUGIN_ID + ".WORKSPACE_SELECTION_DIALOG"; //$NON-NLS-1$ + + /** + * Returns the {@link IDialogSettings} for the given id + * + * @param id + * the id of the dialog settings to get + * @return the {@link IDialogSettings} to pass into the {@link ContainerSelectionDialog} + * @since 3.6 + */ + IDialogSettings getDialogBoundsSettings(String id) { + IDialogSettings settings = DebugUIPlugin.getDefault().getDialogSettings(); + IDialogSettings section = settings.getSection(id); + if (section == null) { + section = settings.addNewSection(id); + } + return section; + } + + /** + * Creates the component set for the ecore folder + * + * @param parent + * the parent to add this component to + */ + private void createEcoreFolderComponent(Composite parent) { + Group group = SWTFactory.createGroup(parent, "Folder with ecore models defining the metamodel", 5, 2, + GridData.FILL_HORIZONTAL); + Composite comp = SWTFactory.createComposite(group, 5, 5, GridData.FILL_BOTH); + GridLayout ld = (GridLayout) comp.getLayout(); + ld.marginWidth = 1; + ld.marginHeight = 1; + GridData gd = new GridData(SWT.BEGINNING, SWT.NORMAL, true, false); + gd.horizontalSpan = 5; + + fEcoreFolderText = SWTFactory.createSingleText(comp, 4); + fEcoreFolderText.getAccessible().addAccessibleListener(new AccessibleAdapter() { + public void getName(AccessibleEvent e) { + e.result = LaunchConfigurationsMessages.CommonTab_6; + } + }); + fEcoreFolderText.addModifyListener(fBasicModifyListener); + + Composite bcomp = SWTFactory.createComposite(comp, 3, 5, GridData.HORIZONTAL_ALIGN_END); + ld = (GridLayout) bcomp.getLayout(); + ld.marginHeight = 1; + ld.marginWidth = 0; + fWorkspaceBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_12, null); + fWorkspaceBrowse.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), + new WorkbenchLabelProvider(), new WorkbenchContentProvider()); + dialog.setTitle(LaunchConfigurationsMessages.CommonTab_13); + dialog.setMessage("Select a folder containing all the ecore models defining the metamodel."); + dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); + dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); + dialog.setDialogBoundsSettings(getDialogBoundsSettings(WORKSPACE_SELECTION_DIALOG), + Dialog.DIALOG_PERSISTSIZE); + if (dialog.open() == IDialogConstants.OK_ID) { + IResource resource = (IResource) dialog.getFirstResult(); + if (resource != null) { + String arg = resource.getFullPath().toString(); + String fileLoc = VariablesPlugin.getDefault().getStringVariableManager() + .generateVariableExpression("workspace_loc", arg); //$NON-NLS-1$ + fEcoreFolderText.setText(fileLoc); + } + } + } + }); + fEcoreFolderBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_7, null); + fEcoreFolderBrowse.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + String filePath = fEcoreFolderText.getText(); + FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); + filePath = dialog.open(); + if (filePath != null) { + fEcoreFolderText.setText(filePath); + } + } + }); + fVariables = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_9, null); + fVariables.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell()); + dialog.open(); + String variable = dialog.getVariableExpression(); + if (variable != null) { + fEcoreFolderText.insert(variable); + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + + } + + /** + * Creates the component set for the ecore folder + * + * @param parent + * the parent to add this component to + */ + private void createMetamodelNameComponent(Composite parent) { + Group group = SWTFactory.createGroup(parent, "Metamodel name", 5, 2, GridData.FILL_HORIZONTAL); + Composite comp = SWTFactory.createComposite(group, 5, 5, GridData.FILL_BOTH); + GridLayout ld = (GridLayout) comp.getLayout(); + ld.marginWidth = 1; + ld.marginHeight = 1; + GridData gd = new GridData(SWT.BEGINNING, SWT.NORMAL, true, false); + gd.horizontalSpan = 5; + + fMetamodelNameText = SWTFactory.createSingleText(comp, 4); + fMetamodelNameText.getAccessible().addAccessibleListener(new AccessibleAdapter() { + public void getName(AccessibleEvent e) { + e.result = LaunchConfigurationsMessages.CommonTab_6; + } + }); + fMetamodelNameText.addModifyListener(fBasicModifyListener); + + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + // TODO Stub de la méthode généré automatiquement + + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + configuration.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, fProjText.getText().trim()); + configuration + .setAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, fEcoreFolderText.getText()); + configuration.setAttribute("mmName", fMetamodelNameText.getText()); + configuration.setAttribute("emf", fEMFCheckButton.getSelection()); + } + + public void initializeFrom(ILaunchConfiguration configuration) { + super.initializeFrom(configuration); + try { + String ecoreFolder = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, + ""); + fEcoreFolderText.setText(ecoreFolder); + + String mmName = configuration.getAttribute("mmName", ""); + fMetamodelNameText.setText(mmName); + + boolean emf = configuration.getAttribute("emf", false); + fEMFCheckButton.setSelection(emf); + + } catch (CoreException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } + } + + @Override + public String getName() { + // TODO Stub de la méthode généré automatiquement + return "Configuration"; + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunchTabGroup.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunchTabGroup.java new file mode 100644 index 0000000000000000000000000000000000000000..9c4d770884604852271df0eabb83ed712320443c --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/CloningMaterialGenerationLaunchTabGroup.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.plugin; + +import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.debug.ui.ILaunchConfigurationTab; + +public class CloningMaterialGenerationLaunchTabGroup extends AbstractLaunchConfigurationTabGroup { + + private ILaunchConfigurationTab[] tabs; + + @Override + public void createTabs(ILaunchConfigurationDialog dialog, String mode) { + tabs = new ILaunchConfigurationTab[] { + // new CommonTab(), // working, but not required + new CloningMaterialGenerationLaunchTab() }; + setTabs(tabs); + + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/EcoreFileFilter.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/EcoreFileFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..0c39b843c2caf90fbd2d6e5d7b8d3067452aeba4 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/plugin/EcoreFileFilter.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.plugin; + +import java.io.File; +import java.io.FileFilter; + + + +public class EcoreFileFilter implements FileFilter { + public boolean accept(File file) { + return file.getName().toLowerCase().endsWith(".ecore"); + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/start/Start.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/start/Start.java new file mode 100644 index 0000000000000000000000000000000000000000..6cc1472de0d70d1efe380a7bab02ef1db520cdbd --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/start/Start.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.start; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +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.xmi.impl.EcoreResourceFactoryImpl; +import org.eclipse.gmt.modisco.java.Model; +import org.eclipse.gmt.modisco.java.generation.files.GenerateJavaExtended; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.modisco.infra.discovery.core.exception.DiscoveryException; +import org.eclipse.modisco.java.discoverer.DiscoverJavaModelFromJavaProject; + +import fr.inria.diverse.cloning.materialgenerator.generators.EMFCodeGenerator; +import fr.inria.diverse.cloning.materialgenerator.generators.EMFCodeGenerator.EMFGenerationException; +import fr.inria.diverse.cloning.materialgenerator.generators.EMFImpl2PImpl; +import fr.inria.diverse.cloning.materialgenerator.generators.ManifestEditor; +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.materialgenerator.tagger.impl.DeepCloningTagger; +import fr.inria.diverse.cloning.materialgenerator.tagger.impl.ShareFieldsOnlyTagger; +import fr.inria.diverse.cloning.materialgenerator.tagger.impl.ShareAllTagger; +import fr.inria.diverse.cloning.materialgenerator.tagger.impl.ShareObjOnlyTagger; +import fr.inria.diverse.cloning.runtime.util.Log; + +public class Start { + + public static void start(Set ecoreFiles, String metamodelName, IJavaProject javaProject, boolean emf) { + Log.info("Starting Cloning material generator"); + + try { + + ResourceSet rs; + if (emf) + rs = EMFCodeGenerator.generate(ecoreFiles, metamodelName, javaProject.getProject()); + else { + + // Loading some ecore files in a resource set (= considered metamodel) + 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); + rs = new ResourceSetImpl(); + } + for (File f : ecoreFiles) + rs.getResource(URI.createFileURI(f.getAbsolutePath()), true); + + // Tagging + Collection taggers = Arrays.asList(new DeepCloningTagger(rs, metamodelName), + new ShareFieldsOnlyTagger(rs, metamodelName), new ShareObjOnlyTagger(rs, metamodelName), + new ShareAllTagger(rs, metamodelName)); + + // Discovering the model from the project + DiscoverJavaModelFromJavaProject discoverer = new DiscoverJavaModelFromJavaProject(); + + discoverer.discoverElement(javaProject, new NullProgressMonitor()); + + // Accessing the obtained model + Resource result = discoverer.getTargetModel(); + Model javaModel = (Model) result.getContents().get(0); + + // Getting the absolute path of the folder + File emfProjectFolder = javaProject.getProject().getLocation().toFile(); + + // String srcOutputFolder = "/home/ebousse/Dev/modelCloning/emf/SomeMetamodel/src"; + String srcOutputFolder = new File(emfProjectFolder, "src").getAbsolutePath(); + + // Calling the partial implementations transformer with one tagger + Model brandNew; + Model toProcess = javaModel; + for (Tagger t : taggers) { + brandNew = new EMFImpl2PImpl(toProcess, t, true).transform2PImpl(srcOutputFolder); + GenerateJavaExtended javaGenerator = new GenerateJavaExtended(toProcess, new File(srcOutputFolder), + new ArrayList()); + javaGenerator.doGenerate(null); + toProcess = brandNew; + } + + //new EMFImpl2PImpl(originalModel, tagger2, true).transform2PImpl(srcOutputFolder); + +// // Generating the code from the obtained model +// GenerateJavaExtended javaGenerator = new GenerateJavaExtended(javaModel, new File(srcOutputFolder), +// new ArrayList()); +// javaGenerator.doGenerate(null); +// +// // Generating the code from the obtained model +// GenerateJavaExtended javaGenerator2 = new GenerateJavaExtended(originalModel, new File(srcOutputFolder), +// new ArrayList()); +// javaGenerator2.doGenerate(null); + + // Adding a dependency in the manifest + ManifestEditor manEdit = new ManifestEditor(javaProject.getProject()); + manEdit.addDependency("fr.inria.diverse.cloning.runtime"); + manEdit.save(); + + javaProject.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); + + // Done + Log.info("Done !"); + } catch (DiscoveryException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (IOException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (EMFGenerationException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } catch (CoreException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } + } +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/Tagger.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/Tagger.java new file mode 100644 index 0000000000000000000000000000000000000000..a0eb014986c4f189b6a4e7311c044d4b2d67205e --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/Tagger.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.tagger; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.runtime.common.ClassTag; + +public interface Tagger { + + public abstract void recomputeTags(); + + public abstract boolean mayTagClassesShareable(); + + public abstract boolean mayTagClassesPartShareable(); + + public abstract String getSuffix(); + + public abstract String getCloningName(); + + public ClassTag getTagOfEClass(EClass c); + + public ResourceSet getMetamodel(); + + public boolean isPropertyShareable(EStructuralFeature property); + + public String getMetamodelName(); + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/AbstractTagger.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/AbstractTagger.java new file mode 100644 index 0000000000000000000000000000000000000000..723796a24097618f0d9fbbc7ea6f4ec087d71ac7 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/AbstractTagger.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.tagger.impl; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.util.EcoreHelper; +import fr.inria.diverse.cloning.runtime.util.Log; + +public abstract class AbstractTagger implements Tagger { + + /** + * Final result of the algorithm, with a tag for each class concerning its "mutability". + */ + protected Map classesTags; + + protected Map propertiesTags; + + protected ResourceSet metamodel; + + protected String metamodelname; + + + @Override + public String getMetamodelName() { + return metamodelname; + } + + public AbstractTagger(ResourceSet metamodel, String metamodelname) { + this.metamodel = metamodel; + this.metamodelname = metamodelname; + propertiesTags = new HashMap(); + classesTags = new HashMap(); + // Finding all classes of the metamodel + for (Resource resource : metamodel.getResources()) + for (Iterator i = resource.getAllContents(); i.hasNext();) { + EObject current = i.next(); + if (current instanceof EClass) + classesTags.put((EClass) current, null); + } + recomputeTags(); + } + + public AbstractTagger(Set metamodel, String metamodelname) { + + } + + protected boolean isMutable(EClass c) { + return (classesTags.get(c) == ClassTag.NOT_SHAREABLE) || (classesTags.get(c) == ClassTag.PARTIALLY_SHAREABLE); + // || (tags.get(c) == ClassTag.canReachMutable); + } + + protected static boolean isPropertyDesignedMutable(EStructuralFeature f) { + //return f.getName().endsWith("_m"); + return EcoreHelper.isPropertyDesignedMutable(f); + } + + + protected enum PropertiesMutability { + allMutable, someMutable, noneMutable + } + + + + @Override + public ClassTag getTagOfEClass(EClass c) { + if (classesTags.containsKey(c)) { + if (classesTags.get(c) == null) + System.out.println("The class " + c.getName() + " has no tag! Tagging problem?"); + return classesTags.get(c); + } else { + Log.error("The class " + c + " is not in the registered metamodel of the cloner!"); + return null; + } + + } + + + @Override + public ResourceSet getMetamodel() { + return metamodel; + } + + @Override + public boolean isPropertyShareable(EStructuralFeature property) { + return propertiesTags.get(property); + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/DeepCloningTagger.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/DeepCloningTagger.java new file mode 100644 index 0000000000000000000000000000000000000000..e430b3fb3a83952d28436e07bf5084249902be01 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/DeepCloningTagger.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.tagger.impl; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.materialgenerator.tagger.Tagger; +import fr.inria.diverse.cloning.runtime.common.ClassTag; + +public class DeepCloningTagger implements Tagger { + + protected String metamodelname; + protected ResourceSet metamodel; + + public DeepCloningTagger(ResourceSet metamodel, String metamodelname) { + this.metamodel = metamodel; + this.metamodelname = metamodelname; + } + + @Override + public void recomputeTags() { + // Nothing to do + } + + @Override + public boolean mayTagClassesShareable() { + return false; + } + + @Override + public String getSuffix() { + return "DeepCloningProxy"; + } + + @Override + public String getCloningName() { + return "DeepCloning"; + } + + @Override + public ClassTag getTagOfEClass(EClass c) { + return ClassTag.NOT_SHAREABLE; + } + + @Override + public ResourceSet getMetamodel() { + return metamodel; + } + + @Override + public boolean isPropertyShareable(EStructuralFeature property) { + return false; + } + + @Override + public String getMetamodelName() { + return metamodelname; + } + + @Override + public boolean mayTagClassesPartShareable() { + return false; + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareAllTagger.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareAllTagger.java new file mode 100644 index 0000000000000000000000000000000000000000..a335ba70ac593a6f733f7a87ce97c43c3c2e4771 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareAllTagger.java @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.tagger.impl; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +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 fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.util.Log; + +/** + * This static class allows to tag all the EClasses of a metamodel in order to determine how it can eventaully be + * cloned, for a normal MutableClassesOnly clone. + * + * @author ebousse + * + */ +public class ShareAllTagger extends AbstractTagger { + + public ShareAllTagger(ResourceSet metamodel, String metamodelname) { + super(metamodel,metamodelname); + } + + /** + * Very simple class used to model sccs, for clarity. + * + * @author ebousse + * + */ + private class StronglyConnectedComponent { + private Set classes; + + public StronglyConnectedComponent() { + classes = new HashSet(); + } + } + + // Tarjan variables + private Map tarjanIndexes; + private Map tarjanLowlinks; + private Stack tarjanS; + private int tarjanIndex; + private Set tarjanResult; + + /** + * From https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorith Main operation that + * implements the main operation of the tarjan algorithm. Computes StronglyConnectedComponents, and tags classes in + * each as soon as they are computed. + * + * + * @param vertices + * the EClasses to consider + */ + private void tarjanWithTagging(Set vertices) { + tarjanIndexes = new HashMap(); + tarjanLowlinks = new HashMap(); + tarjanS = new Stack(); + tarjanIndex = 0; + tarjanResult = new HashSet(); + for (EClass v : vertices) { + if (!tarjanIndexes.containsKey(v)) { + tarjanWithTaggingOnVertex(v); + } + } + + + } + + /** + * Main code of the tarjan algorithm. + * + * @param v + */ + private void tarjanWithTaggingOnVertex(EClass v) { + + + // Set the depth index for v to the smallest unused index + tarjanIndexes.put(v, tarjanIndex); + tarjanLowlinks.put(v, tarjanIndex); + tarjanIndex = tarjanIndex + 1; + tarjanS.push(v); + + // Computing successors + Set successors = new HashSet(); + for (EReference ref : v.getEAllReferences()) + successors.add(ref.getEReferenceType()); + + // Consider successors of v + for (EClass w : successors) { + if (!tarjanIndexes.containsKey(w)) { + // Successor w has not yet been visited; recurse on it + tarjanWithTaggingOnVertex(w); + tarjanLowlinks.put(v, Math.min(tarjanLowlinks.get(v), tarjanLowlinks.get(w))); + } else if (tarjanS.contains(w)) { + // Successor w is in stack S and hence in the current SCC + tarjanLowlinks.put(v, Math.min(tarjanLowlinks.get(v), tarjanIndexes.get(w))); + } + } + + + // If v is a root node, pop the stack and generate an SCC + if (tarjanLowlinks.get(v).equals(tarjanIndexes.get(v))) { + //System.out.println("PLAP"); + + StronglyConnectedComponent scc = new StronglyConnectedComponent(); + EClass w; + do { + w = tarjanS.pop(); + scc.classes.add(w); + } while (w != v); + + // BONUS (only part not in Tarjan): computing tags + // Possible because Tarjan guarantees that + // "no strongly connected component will be identified before any of its successors." + computeMutabilityOfScc(scc); + // End BONUS + + tarjanResult.add(scc); + + } + } + + /** + * To me used as soon as some SCC is found by the Tarjan algorithm. Will iterate over all classes of the SCC, and + * tags them for mutability. + * + * @param scc + * A StronglyConnectedComponent freshly computed in Tarjan. + */ + private void computeMutabilityOfScc(StronglyConnectedComponent scc) { + + // The set of classes to process + Set remainingClasses = new HashSet(); + remainingClasses.addAll(scc.classes); + + // We keep track whether the SCC can reach a mutable somewher or not + boolean hasReachableMutable = false; + boolean secondPass = false; + + // We loop until we tagged all classes of the scc + while (remainingClasses.size() != 0) { + + // At each iteration, we will remove some classes + Set toRemove = new HashSet(); + + // For each remaining class + for (EClass c : remainingClasses) { + + // We must determine if the class has mutable properties + // (ie. with "_m" or pointing to a mutable class) + boolean hasMutables = false; + + // If it has readonly properties + // (ie without "_m" and not pointing to a mutable class) + boolean hasReadonlys = false; + + // And whether we are over with the class or not + boolean allSettled = true; + + // We go through all its properties + for (EStructuralFeature prop : c.getEAllStructuralFeatures()) { + + // Maybe we already know + if (propertiesTags.containsKey(prop)) { + if (propertiesTags.get(prop)) { + hasReadonlys = true; + } else { + hasMutables = true; + } + } + // Or we have to (try to) compute it + else { + + // If the property is mutable, the class is mutable and we're settled for this property + if (isPropertyDesignedMutable(prop)) { + hasMutables = true; + hasReachableMutable = true; + propertiesTags.put(prop, false); + } + // Else we check if it's a reference + else if (prop instanceof EReference) { + EClass type = ((EReference) prop).getEReferenceType(); + + // Either the type is tagged already (should be the case if from another scc) + if (classesTags.containsKey(type) && classesTags.get(type) != null) { + ClassTag refTag = classesTags.get(type); + if (refTag == ClassTag.NOT_SHAREABLE || refTag == ClassTag.PARTIALLY_SHAREABLE) { + hasMutables = true; + hasReachableMutable = true; + propertiesTags.put(prop, false); + } + else if (refTag == ClassTag.COMPLETELY_SHAREABLE) { + hasReadonlys = true; + propertiesTags.put(prop, true); + } + + } + + // If not, maybe we know whether the scc can reach a mutable or not + else if (hasReachableMutable && scc.classes.contains(type)) { + hasMutables = true; + hasReachableMutable = true; + propertiesTags.put(prop, false); + } + + // If not, maybe this is the second pass, thus we MUST be readonly + else if (secondPass) { + hasReadonlys = true; + propertiesTags.put(prop, true); + } + + // If not, we must wait until we know... + else { + allSettled = false; + } + + } + // If it's an attribute, it must be readonly + else { + hasReadonlys = true; + propertiesTags.put(prop, true); + } + } + } + + // After analyzing the class, if all settled, we tag it + if (allSettled) { + toRemove.add(c); + + if (hasMutables && hasReadonlys) + classesTags.put(c, ClassTag.PARTIALLY_SHAREABLE); + else if (hasMutables && !hasReadonlys) + classesTags.put(c, ClassTag.NOT_SHAREABLE); + else + classesTags.put(c, ClassTag.COMPLETELY_SHAREABLE); + } + + } + + remainingClasses.removeAll(toRemove); + secondPass = true; + + } + + + } + + /* + * (non-Javadoc) + * + * @see fr.diverse.fancyemfcloning.tagger.Tagger#recomputeTags() + */ + @Override + public void recomputeTags() { + Log.info("Tagging with ShareAllTagger."); + tarjanWithTagging(classesTags.keySet()); + Log.info("Computed mutabilities:"); + Log.plusLevel(); + for (EClass c : classesTags.keySet()) { + Log.info(c.getName() + ": " + classesTags.get(c)); + } + Log.minusLevel(); + } + + /* + * (non-Javadoc) + * + * @see fr.diverse.fancyemfcloning.tagger.Tagger#mayTagClassesReadonly() + */ + @Override + public boolean mayTagClassesShareable() { + return true; + } + + /* + * (non-Javadoc) + * + * @see fr.diverse.fancyemfcloning.tagger.Tagger#getSuffix() + */ + @Override + public String getSuffix() { + return "ShareAllProxy"; + } + + /* + * (non-Javadoc) + * + * @see fr.diverse.fancyemfcloning.tagger.Tagger#getCloningName() + */ + @Override + public String getCloningName() { + return "ShareAll"; + } + + @Override + public boolean mayTagClassesPartShareable() { + return true; + } + + + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareFieldsOnlyTagger.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareFieldsOnlyTagger.java new file mode 100644 index 0000000000000000000000000000000000000000..b69a419c84330139b3c88a66b0ae858d1af0be84 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareFieldsOnlyTagger.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.tagger.impl; + +import java.util.Iterator; + +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.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.util.Log; + +public class ShareFieldsOnlyTagger extends AbstractTagger { + + public ShareFieldsOnlyTagger(ResourceSet metamodel, String metamodelname) { + super(metamodel, metamodelname); + } + + + @Override + public void recomputeTags() { + Log.info("Tagging with ShareFieldsOnlyTagger."); + for (Resource res : metamodel.getResources()) { + for (Iterator i = res.getAllContents(); i.hasNext();) { + EObject next = i.next(); + if (next instanceof EClass) { + EClass c = (EClass) next; + boolean hasReadonlys = false; + // First attributes + for (EAttribute att : c.getEAllAttributes()) { + if (isPropertyDesignedMutable(att)) + propertiesTags.put(att, false); + else { + propertiesTags.put(att, true); + hasReadonlys = true; + } + } + // Then references, all mutable + for (EReference ref : c.getEAllReferences()) { + propertiesTags.put(ref, false); + } + + if (hasReadonlys) + classesTags.put(c, ClassTag.PARTIALLY_SHAREABLE); + else + classesTags.put(c, ClassTag.NOT_SHAREABLE); + } + } + } + Log.info("Computed mutabilities:"); + Log.plusLevel(); + for (EClass c : classesTags.keySet()) { + Log.info(c.getName() + " : " + classesTags.get(c)); + } + Log.minusLevel(); + + } + + @Override + public boolean mayTagClassesShareable() { + return false; + } + + @Override + public String getSuffix() { + return "ShareFieldsOnlyProxy"; + } + + @Override + public String getCloningName() { + return "ShareFieldsOnly"; + } + + + @Override + public boolean mayTagClassesPartShareable() { + return true; + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareObjOnlyTagger.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareObjOnlyTagger.java new file mode 100644 index 0000000000000000000000000000000000000000..1f825eb8b05e0a92c41f1716e043d903569532a5 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/tagger/impl/ShareObjOnlyTagger.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.tagger.impl; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.runtime.common.ClassTag; + +public class ShareObjOnlyTagger extends ShareAllTagger { + + public ShareObjOnlyTagger(ResourceSet metamodel, String metamodelname) { + super(metamodel, metamodelname); + } + + @Override + public String getSuffix() { + return "ShareObjOnlyProxy"; + } + + @Override + public String getCloningName() { + return "ShareObjOnly"; + } + + @Override + public ClassTag getTagOfEClass(EClass c) { + ClassTag result = super.getTagOfEClass(c); + if (result == ClassTag.PARTIALLY_SHAREABLE) + return ClassTag.NOT_SHAREABLE; + else + return result; + } + + @Override + public boolean isPropertyShareable(EStructuralFeature property) { + return false; + } + + @Override + public boolean mayTagClassesShareable() { + return super.mayTagClassesShareable(); + } + + @Override + public boolean mayTagClassesPartShareable() { + return false; + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/util/CodeGeneration.java b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/util/CodeGeneration.java new file mode 100644 index 0000000000000000000000000000000000000000..f29e055bf72356bc60936cb9d8c321847c10b234 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/src/fr/inria/diverse/cloning/materialgenerator/util/CodeGeneration.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.materialgenerator.util; + +import java.util.Map; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.formatter.CodeFormatter; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.TextEdit; + +public class CodeGeneration { + + /** + * Sets the first character of a String in upper case. + * + * @param in + * The String to be firstupped + * @return The string firstUpped. + */ + public static String firstCharUp(String in) { + return Character.toUpperCase(in.charAt(0)) + in.substring(1); + } + + + /** + * From + * http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2F + * jdt%2Fcore%2Fformatter%2Fpackage-summary.html + * + * @param source + * The raw java source code to format. + * @return Formatted java code. + */ + public static String formatJavaCode(String source) { + // take default Eclipse formatting options + @SuppressWarnings("unchecked") + Map options = DefaultCodeFormatterConstants.getEclipseDefaultSettings(); + + // initialize the compiler settings to be able to format 1.7 code + options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7); + options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7); + + // instantiate the default code formatter with the given options + final CodeFormatter codeFormatter = ToolFactory.createCodeFormatter(options); + + final TextEdit edit = codeFormatter.format(CodeFormatter.K_COMPILATION_UNIT, // format a compilation unit + source, // source to format + 0, // starting position + source.length(), // length + 0, // initial indentation + System.getProperty("line.separator") // line separator + ); + + IDocument document = new Document(source); + try { + edit.apply(document); + } catch (MalformedTreeException e) { + e.printStackTrace(); + } catch (org.eclipse.jface.text.BadLocationException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } + + // display the formatted string on the System out + return document.get(); + } + + +} diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/testdata/mm8.ecore b/moclodash/fr.inria.diverse.cloning.materialgenerator/testdata/mm8.ecore new file mode 100644 index 0000000000000000000000000000000000000000..d246c9a82ff669d5af90c52f745c8f9ae16bc289 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/testdata/mm8.ecore @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.materialgenerator/testdata/mm8.ecorediag b/moclodash/fr.inria.diverse.cloning.materialgenerator/testdata/mm8.ecorediag new file mode 100644 index 0000000000000000000000000000000000000000..6c19aa581c430754766bceba58f4c85556dce438 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.materialgenerator/testdata/mm8.ecorediag @@ -0,0 +1,5201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.runtime/.classpath b/moclodash/fr.inria.diverse.cloning.runtime/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..3bc247511f0f2d8c7cda0c9514a4e1d2c7ab5e23 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/moclodash/fr.inria.diverse.cloning.runtime/.gitignore b/moclodash/fr.inria.diverse.cloning.runtime/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5e56e040ec0902e58df8573adaec65c5da6e9304 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/moclodash/fr.inria.diverse.cloning.runtime/.project b/moclodash/fr.inria.diverse.cloning.runtime/.project new file mode 100644 index 0000000000000000000000000000000000000000..6ccc0549271433d4470de3b5186a949df5353166 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/.project @@ -0,0 +1,28 @@ + + + fr.inria.diverse.cloning.runtime + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + + diff --git a/moclodash/fr.inria.diverse.cloning.runtime/META-INF/MANIFEST.MF b/moclodash/fr.inria.diverse.cloning.runtime/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000000000000000000000000000000..c7b8f11f6825b74b21f9906688b9ce4ce3c6a6a4 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: fr.inria.diverse.cloning.base +Bundle-SymbolicName: fr.inria.diverse.cloning.runtime;singleton:=true +Bundle-Version: 0.1.0.qualifier +Require-Bundle: org.eclipse.emf.ecore;bundle-version="2.9.1", + org.eclipse.emf.ecore.xmi;bundle-version="2.9.1", + org.eclipse.ui.console;bundle-version="3.5.200", + org.eclipse.jface;bundle-version="3.9.1", + org.eclipse.ui;bundle-version="3.105.0" +Export-Package: fr.inria.diverse.cloning.runtime.cloner, + fr.inria.diverse.cloning.runtime.cloner.impl, + fr.inria.diverse.cloning.runtime.common, + fr.inria.diverse.cloning.runtime.emfextension, + fr.inria.diverse.cloning.runtime.emfextension.impl, + fr.inria.diverse.cloning.runtime.util +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-ClassPath: . diff --git a/moclodash/fr.inria.diverse.cloning.runtime/build.properties b/moclodash/fr.inria.diverse.cloning.runtime/build.properties new file mode 100644 index 0000000000000000000000000000000000000000..34d2e4d2dad529ceaeb953bfcdb63c51d69ffed2 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/moclodash/fr.inria.diverse.cloning.runtime/pom.xml b/moclodash/fr.inria.diverse.cloning.runtime/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..093bcd2c379a0081a08bd18504699433a1c623dd --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/pom.xml @@ -0,0 +1,27 @@ + + + + 4.0.0 + fr.inria.diverse.cloning + fr.inria.diverse.cloning.runtime + 0.1.0-SNAPSHOT + eclipse-plugin + + + fr.inria.diverse.cloning + moclodash + 0.1.0-SNAPSHOT + + + + diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/cloner/Cloner.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/cloner/Cloner.java new file mode 100644 index 0000000000000000000000000000000000000000..3e9a19b57a5fb1204a9c20f2af76c1dc72300448 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/cloner/Cloner.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.cloner; + +import java.io.File; + +import org.eclipse.emf.ecore.resource.ResourceSet; + +/** + * Defines a class in which a cloning technique is implemented. + * + * @author ebousse + * + */ +public interface Cloner { + + /** + * Considering a model stored in a ResourceSet, computes a clone of the model. + * + * @param model + * The model to clone. + * @param folder + * The name of the folder in which to store the model to clone, which will be created in the cloned model + * folder + * @return The cloned model. + */ + public ResourceSet clone(ResourceSet model, String folderName);//,boolean light); + + public ResourceSet clone(ResourceSet cloned, File outputFolder);//,boolean light); + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/cloner/impl/ClonerImpl.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/cloner/impl/ClonerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..e85c4ce3c32a12d37bbc01ddda42f25fbfb20bf2 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/cloner/impl/ClonerImpl.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.cloner.impl; + +import java.io.File; +import java.util.Iterator; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +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.xmi.impl.XMIResourceImpl; + +import fr.inria.diverse.cloning.runtime.cloner.Cloner; +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.common.CloningMaterial; +import fr.inria.diverse.cloning.runtime.common.MetamodelTags; +import fr.inria.diverse.cloning.runtime.emfextension.impl.LooseCopier; +import fr.inria.diverse.cloning.runtime.emfextension.impl.LooseResource; + +/** + * Self containing class with the cloning algorithm. + * + * @author ebousse + * + */ +public class ClonerImpl implements Cloner { + + private CloningMaterial cloningMaterial; + + public ClonerImpl(CloningMaterial cm) { + super(); + cloningMaterial = cm; + } + + private ResourceSet clone(ResourceSet cloned, File outputFolder, String folderName) {//, boolean light) { + + // Creating empty clone resource set + ResourceSet clone = new ResourceSetImpl(); + //clone.cre + + // Either we make a light clone, or not + /*Copier copier = null; + if (light) + copier = cloningMaterial.createCopier(); + else + copier = new LooseCopier();*/ + LooseCopier copier = cloningMaterial.createCopier(); + + // Getting the tags of the metamodel + MetamodelTags tags = cloningMaterial.getTags(); + + // Cloning all resources + for (Resource r : cloned.getResources()) { + + URI uri = null; + if (outputFolder == null) { + // Getting the complete file name + String filename = r.getURI().segmentsList().get(r.getURI().segmentsList().size() - 1); + // Preparing the URI of the new resource (with a specific 'folder') + uri = r.getURI().trimSegments(1).appendSegment(folderName).appendSegment(filename); + } else { + uri = URI.createFileURI(outputFolder.getAbsolutePath()); + } + + // Creating the new Resource... + Resource resourceClone = null; + // LooseResource if there are readonly objects that might be shared among models + if (tags.mayTagClassesShareable()) { + resourceClone = new LooseResource(tags); + resourceClone.setURI(uri); + clone.getResources().add(resourceClone); + } + // Or regular Resource, if not + else { + //resourceClone = clone.createResource(uri); + resourceClone = new XMIResourceImpl(uri); + //resourceClone.setURI(uri); + clone.getResources().add(resourceClone); + } + + // Copying objects (but not the references, and only tagged mutable ones) + for (Iterator i = r.getAllContents(); i.hasNext();) { + EObject o = i.next(); + ClassTag tag = tags.getTagOf(o.eClass()); + + // We only put the copied object in the resource if not contained already + if (o.eContainer() == null) { + switch (tag) { + case NOT_SHAREABLE: // here the copier should always produce a regular copy + resourceClone.getContents().add(copier.copy(o)); + break; + case PARTIALLY_SHAREABLE: // here the copier will decide whether a light version can/should be produced + resourceClone.getContents().add(copier.copy(o)); + break; + case COMPLETELY_SHAREABLE: // no copy, shared object + resourceClone.getContents().add(o); + break; + } + } else { + switch (tag) { + case NOT_SHAREABLE: // here the copier should always produce a regular copy + copier.copy(o); + break; + case PARTIALLY_SHAREABLE: // here the copier will decide whether a light version can/should be produced + copier.copy(o); + break; + case COMPLETELY_SHAREABLE: // no copy, shared object + break; + } + } + + } + } + + // Resolving references (all of them, even between resources of the clone and between the clone and the origin) + copier.copyReferences(); + + // Returning the obtained clone + return clone; + } + + @Override + public ResourceSet clone(ResourceSet cloned, File outputFolder) {//, boolean light) { + return clone(cloned, outputFolder, "NOTHING");//, light); + } + + @Override + public ResourceSet clone(ResourceSet cloned, String folderName) {//, boolean light) { + return clone(cloned, null, folderName);//, light); + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/ClassTag.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/ClassTag.java new file mode 100644 index 0000000000000000000000000000000000000000..5e5e7a2fd7beb8e20cddce5815fe39f62345153a --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/ClassTag.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.common; + +/** + * From a cloning kind point of view a class is either + * - completely readonly (no property change change), thus no need to clone it + * - completely mutable (all properties can change), thus must be cloned completely + * - partially mutable (some properties can change) OR can reach a mutable , thus can be cloned partially or completely + * @author ebousse + * + */ +public enum ClassTag { + COMPLETELY_SHAREABLE, + NOT_SHAREABLE, + PARTIALLY_SHAREABLE, +} + diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/CloningMaterial.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/CloningMaterial.java new file mode 100644 index 0000000000000000000000000000000000000000..37e69bcee2a79364b993a7092aa2c27e336dfb65 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/CloningMaterial.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.common; + +import fr.inria.diverse.cloning.runtime.emfextension.impl.LooseCopier; + +public interface CloningMaterial { + + public MetamodelTags getTags(); + public LooseCopier createCopier(); + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/MetamodelTags.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/MetamodelTags.java new file mode 100644 index 0000000000000000000000000000000000000000..1038e6edc6cc7a93b6cbacb0615c21fbce7d7499 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/common/MetamodelTags.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.common; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + + +/** + * Singleton class that stores the cloning tags of a given metamodel for a given cloning technique. + * + * @author ebousse + * + */ +public interface MetamodelTags { + + public ClassTag getTagOf(EClass eClass); + + public boolean mayTagClassesShareable(); + + public boolean isPropertyShareable(EStructuralFeature prop); + + /** + * Number of _completely_ shareable classes / total classes + * @return + */ + public double getShareableClassesRatio(); + + + /** + * Number of _partially_ shareable classes / total classes + * @return + */ + public double getPartShareableClassesRatio(); + + /** + * Number of shareable properties in shareable classes / total properties + * @return + */ + public double getIsolatedShareablePropertiesRatio(); + + /** + * Number of shareable properties per part shareable classe + * @return + */ + public double getShareablePropertiesInPartShareableClassesDensity(); + + + /** + * Number of shareable properties per shareable classe + * @return + */ + public double getShareablePropertiesInShareableClassesDensity(); + + + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/ShareableEObject.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/ShareableEObject.java new file mode 100644 index 0000000000000000000000000000000000000000..26c49533dabeb2f40da95844e25145742175e4ec --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/ShareableEObject.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.emfextension; + +import org.eclipse.emf.ecore.EObject; + + +/** + * Should allow to know in what you are contained. + * But not "required" for objects that are shared and contained in a shared reference... + * Thus not used for now. + * + * @author ebousse + * + */ +public interface ShareableEObject extends EObject { + + + /** + * Gives access to the EObject or the Resource that contains this object + * in a given context (a ResourceSet, ie. a model). + * Relevant only if this object is shared between multiple models. + * + * @param context The context in which this object in contained, ie a model + * @return Either a Resource or an EObject that contains this object in the given context. + */ + //public Object getContainerOrResourceInContext(ResourceSet context); + + + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/AbstractShareableEObject.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/AbstractShareableEObject.java new file mode 100644 index 0000000000000000000000000000000000000000..5b3bbda226b892447a80dbdaf8908817787471cd --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/AbstractShareableEObject.java @@ -0,0 +1,335 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.emfextension.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.MinimalEObjectImpl; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.Resource.Internal; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.common.MetamodelTags; +import fr.inria.diverse.cloning.runtime.util.EcoreHelper; + +// Default genmodel : org.eclipse.emf.ecore.impl.MinimalEObjectImpl$Container + +/** + * Defines an EMF object that can be contained in multiple objects, as long as + * these objects are in different ResourceSets. Yet, it keeps a single "main" + * container, at all time (eContainer). + * + * @author ebousse + * + */ +public abstract class AbstractShareableEObject extends MinimalEObjectImpl.Container {// implements + // ShareableEObject + // { + + /** + * Internal class to store the context temporarily + * + * @author ebousse + * + */ + private class ReadonlyContext { + // storage place for the main container in the main resourceset + protected InternalEObject storedMainContainer; + // storage place for the main resource + protected Resource storedResource; + + public ReadonlyContext(AbstractShareableEObject o) { + this.storedMainContainer = (InternalEObject) o.eContainer(); + this.storedResource = o.eResource(); + } + + public InternalEObject getContainer() { + return storedMainContainer; + } + + public Resource getResource() { + return storedResource; + } + } + + /** + * All the containers of the object that are in a clone model. + */ + protected Map additionnalContainersOrResources; + + /** + * Maps are initialized only at first usage, in order to save some memory + * (despite) + */ + protected AbstractShareableEObject() { + super(); + } + + /** + * Simple util operation to find the resource set of an object. + * + * @param o + * The object to analyze. + * @return The resource set of o, or null if there is none. + */ + private static ResourceSet findResourceSet(InternalEObject o) { + if (o.eResource() != null) + return o.eResource().getResourceSet(); + else + return null; + } + + private static Resource findResource(InternalEObject o) { + if (o.eResource() != null) + return o.eResource(); + else if (o.eContainer() != null) + return findResource((InternalEObject) o.eContainer()); + else + return null; + } + + /** + * Switch to the context of another object. + * + * @param otherEnd + * @return + */ + protected ReadonlyContext changeContext(InternalEObject otherEnd) { + + // We find the resource set we are located in + ResourceSet currentRS = findResourceSet(this); + Resource otherResource = findResource(otherEnd); + ResourceSet otherRS = findResourceSet(otherEnd); + + // We must only change the context if the otherEnd is in a LooseResource + // in another ResourceSet + // AND if we are considered readonly by the cloning technique of the + // LooseResource + boolean toChange = (otherResource != null) + && (otherResource instanceof LooseResource) + && (((LooseResource) (otherResource)).getTags().getTagOf(this.eClass()) == ClassTag.COMPLETELY_SHAREABLE) + && (otherRS != null) && (otherRS != currentRS); + + // If we do change the context + if (toChange) { + + // We store the context + ReadonlyContext context = new ReadonlyContext(this); + + // We get the resource set in which "things happen" + ResourceSet otherResourceSet = otherEnd.eResource().getResourceSet(); + + // We initialize the maps at the first usage + // if (this.additionnalContainersOrResources == null) { + // additionnalContainersOrResources = new HashMap(1); + // } + + // If we don't have entries for the otherResourceSet, + // we create ones with 'null' (ie not contained in this resource + // yet) + // if + // (!this.additionnalContainersOrResources.containsKey(otherResourceSet)) + // { + // this.additionnalContainersOrResources.put(otherResourceSet, + // null); + // } + + // We remove ourselves from a resource + if (this.eResource() != null) + this.eResource().getContents().remove(this); + + // We temporarily change the container (which might of course erase + // the resource) + + Object container; + if (this.additionnalContainersOrResources == null) + container = null; + else + container = this.additionnalContainersOrResources.get(otherResourceSet); + + if (container != null) { + if (container instanceof InternalEObject) { + this.eBasicSetContainer((InternalEObject) container); + } + if (container instanceof Resource) { + ((Resource) container).getContents().add(this); + } + } else { + this.eBasicSetContainer(null); + this.setResourceNonInverse(null); + } + + /* + * InternalEObject otherCont = (InternalEObject) + * this.additionnalContainersAndResources.get(otherResourceSet)[0]; + * + * + * // We temporarily change the resource, if the container was null + * if (otherCont == null) { Resource otherResource = (Resource) + * this.additionnalContainersAndResources.get(otherResourceSet)[1]; + * if (otherResource != null) otherResource.getContents().add(this); + * } + */ + + // And we return the context for further restore + return context; + + } + + // If we don't change the context, we explicitly return null + else { + return null; + } + } + + /** + * Restore a previously stored context. + * + * @param context + */ + protected void restoreContext(ReadonlyContext context, InternalEObject otherEnd) { + + // If null, nothing to restore + if (context != null) { + + // We find the resource set we are located in + ResourceSet currentResourceSet = findResourceSet(this); + + boolean storeContainer = true; + + Resource otherResource = findResource(otherEnd); + MetamodelTags tags = null; + if (otherResource != null && otherResource instanceof LooseResource) + tags = ((LooseResource) (otherResource)).getTags(); + // if (tags != null && + // tags.isPropertyShareable(this.eContainmentFeature())) { + if (tags != null && !EcoreHelper.isPropertyDesignedMutable(this.eContainmentFeature())) { + storeContainer = false; + } + + if (storeContainer) { + // We initialize the maps at the first usage + if (this.additionnalContainersOrResources == null) { + additionnalContainersOrResources = new HashMap(1); + } + + // We store the current context in our map + if (this.eContainer != null) + this.additionnalContainersOrResources.put(currentResourceSet, this.eContainer); + else + this.additionnalContainersOrResources.put(currentResourceSet, this.eResource()); + + } + + // And we restore the context + if (this.eResource() != null) + this.eResource().getContents().remove(this); + this.eBasicSetContainer(context.getContainer()); + if (context.getContainer() == null && context.getResource() != null) + context.getResource().getContents().add(this); + + } + } + + @Override + /* + * (non-Javadoc) Appelé lorsque this est ajouté à otherEnd + * + * @see + * org.eclipse.emf.ecore.impl.BasicEObjectImpl#eInverseAdd(org.eclipse.emf + * .ecore.InternalEObject, int, java.lang.Class, + * org.eclipse.emf.common.notify.NotificationChain) + */ + public NotificationChain eInverseAdd(InternalEObject otherEnd, int featureID, + Class baseClass, NotificationChain msgs) { + + // Changing the context + ReadonlyContext context = changeContext(otherEnd); + + // Actual call + NotificationChain result = super.eInverseAdd(otherEnd, featureID, baseClass, msgs); + + // Restoring the context + restoreContext(context, otherEnd); + + // And finally we return the NotificationChain + return result; + } + + @Override + /* + * (non-Javadoc) Appelé lorsque this est retiré de otherEnd + * + * @see + * org.eclipse.emf.ecore.impl.BasicEObjectImpl#eInverseRemove(org.eclipse + * .emf.ecore.InternalEObject, int, java.lang.Class, + * org.eclipse.emf.common.notify.NotificationChain) + */ + public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, + Class baseClass, NotificationChain msgs) { + + // Changing the context + ReadonlyContext context = changeContext(otherEnd); + + // Actual call + NotificationChain result = super.eInverseRemove(otherEnd, featureID, baseClass, msgs); + + // handling the removal from the hashmap, if required + Resource otherResource = findResource(otherEnd); + ResourceSet otherRS = findResourceSet(otherEnd); + //MetamodelTags tags = null; + if (otherResource != null && otherResource instanceof LooseResource) { + // tags = ((LooseResource) (otherResource)).getTags(); + // if (tags != null && + // !EcoreHelper.isPropertyDesignedMutable(this.eContainmentFeature())) + // { + this.additionnalContainersOrResources.remove(otherRS); + if (this.additionnalContainersOrResources.size() == 0) + this.additionnalContainersOrResources = null; + } + + // Restoring the context + restoreContext(context, otherEnd); + + // And finally we return the NotificationChain + return result; + } + + /** + * Added method that allow one to change the resource of the object without + * changing what resources think they contain. Created for the "save" method + * of LooseResource, that must briefly change the resources of the elements + * of a model for correct referencing between resources. + * + * @param resource + * The resource to set in the object. The resource won't be + * changed. + */ + public void setResourceNonInverse(Internal resource) { + eSetDirectResource(resource); + } + + // @Override + // public Object getContainerOrResourceInContext(ResourceSet context) { + // if (findResourceSet(this) == context) + // return this.eContainer(); + // else if (this.additionnalContainersOrResources.containsKey(context)) + // return this.additionnalContainersOrResources.get(context); + // else + // return null; + // } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/LooseCopier.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/LooseCopier.java new file mode 100644 index 0000000000000000000000000000000000000000..441386bdf439f2397dda63bf08cb66a6935bb2c0 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/LooseCopier.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.emfextension.impl; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.util.EcoreUtil.Copier; +import org.eclipse.emf.ecore.util.InternalEList; + +/** + * Customized Copier that will ignore containment relationships and treat them the same way as simple references. + * + * + * @author ebousse + * + */ +public class LooseCopier extends Copier { + + private static final long serialVersionUID = -3587653043296819827L; + + private Set context; + + /** + * Temporarily change the EClass of some EObject by setting its containments as simple references. + * + * @param o + * The considered EObject. + * @return The stored context, that is the list of the changed ERefences. + */ + private Set removeContainmentsFromClassOfObject(EObject o) { + Set context = new HashSet(); + for (EReference r : o.eClass().getEAllContainments()) { + context.add(r); + r.setContainment(false); + } + return context; + } + + /** + * Restores the contaiments of some references. + * + * @param context + * The list of references. + */ + private void restoreContainments(Set context) { + for (EReference r : context) + r.setContainment(true); + } + + // ------------------ + + @Override + /* + * (non-Javadoc) + * + * @see org.eclipse.emf.ecore.util.EcoreUtil.Copier#copy(org.eclipse.emf.ecore .EObject) + */ + public EObject copy(EObject eObject) { + + // Saving context (ie. what are the containments of the class of the copied objects) + // and changing it (ie. removing all containments) + Set context = removeContainmentsFromClassOfObject(eObject); + + // Calling copier copy code + EObject result = super.copy(eObject); + + // Restoring context + restoreContainments(context); + + // And returning result + return result; + } + + @Override + public void copyReferences() { + + // Saving context (ie. what are the containments of the _classes_ of the copied objects) + // and changing it (ie. removing all containments) + context = new HashSet(); + // Set context = new HashSet(); + for (EObject o : this.keySet()) + context.addAll(removeContainmentsFromClassOfObject(o)); + + // Calling copier copyReferences code + super.copyReferences(); + + // Restoring context + restoreContainments(context); + + } + + @SuppressWarnings("unchecked") + @Override + protected void copyReference(EReference eReference, EObject eObject, EObject copyEObject) { + + boolean ok = true; + + // Little hack: we avoid to try to copy from the same collection in the same collection + // This might happen with "light" cloning, as the clone object will return the same collection as the cloned + // And EMF copier does not handle that correctly :) + if (eObject.eIsSet(eReference)) { + if (eReference.isMany()) { + InternalEList source = (InternalEList) eObject.eGet(eReference); + InternalEList targetMany = (InternalEList) copyEObject.eGet(getTarget(eReference)); + if (source == targetMany) { + ok = false; + } + } + } + + // We make the copy... if not same collection + if (ok) + super.copyReference(eReference, eObject, copyEObject); + + + + + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/LooseResource.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/LooseResource.java new file mode 100644 index 0000000000000000000000000000000000000000..4130b62f6755f51c7ee0c800192f1a459893fb29 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/emfextension/impl/LooseResource.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.emfextension.impl; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; + +import fr.inria.diverse.cloning.runtime.common.ClassTag; +import fr.inria.diverse.cloning.runtime.common.MetamodelTags; + +public class LooseResource extends XMIResourceImpl { + + /** + * A LooseResource considers readonly classes that a given cloning technique + * consider readonly. Thus it needs to know ther cloner that created it. + */ + private MetamodelTags tags; + + /** + * The default constructor is private, because such resources can only be + * constructed with tags, otherwise invalid. + */ + private LooseResource() {}; + + /** + * Constructs a LooseResource to build a clone made by a specific cloning + * technique. + * + * @param c + * The cloning technique tagger. + */ + public LooseResource(MetamodelTags t) { + this(); + this.tags = t; + } + + /** + * We might need to know the cloner, in order to know what objects are + * readonly for this resource. + * + * @return + */ + public MetamodelTags getTags() { + return tags; + } + + /** + * We have to extend the containment list used by XMIResourceImpl, in order + * to break the containment for readonly objects. + * Note that this hack does not prevent a regular Resource from removing + * + * @author ebousse + * + * @param + */ + protected class LooseContentsEList extends + ContentsEList { + + private static final long serialVersionUID = 1410188721350066354L; + + @Override + public NotificationChain inverseAdd(E object, + NotificationChain notifications) { + InternalEObject eObject = (InternalEObject) object; + // We only allow Readonly (from the cloning technique pov) objects + // to be in multiple resources at once + if (!(LooseResource.this.tags.getTagOf(eObject.eClass()) == ClassTag.COMPLETELY_SHAREABLE)) + notifications = eObject.eSetResource(LooseResource.this,notifications); + LooseResource.this.attached(eObject); + return notifications; + } + + @Override + public NotificationChain inverseRemove(E object, + NotificationChain notifications) { + InternalEObject eObject = (InternalEObject) object; + if (LooseResource.this.isLoaded || unloadingContents != null) { + LooseResource.this.detached(eObject); + } + // We only allow Readonly (from the cloning technique pov) objects + // to be in multiple resources at once + if (!(LooseResource.this.tags.getTagOf(eObject.eClass()) == ClassTag.COMPLETELY_SHAREABLE)) + return eObject.eSetResource(null, notifications); + else + return notifications; + } + + } + + protected EList realContents; + + @Override + /** + * "Overrides" the 'contents' property of the + * extended class. + */ + public EList getContents() { + if (realContents == null) { + realContents = new LooseContentsEList(); + } + return realContents; + } + + /** + * Change the resource of all "contained" readonly objects, and store their + * real resources + * + * Can maybe be optimized by only looking at objects referenced by this resource. + * + * Could maybe be optimized be looking at all references of the resource + * that go outside the resource (thus into another resource of the resource set) + * Such referenced objects are the only ones that should be contextified. + * @return The context, that is a set of objects and their theoretical resource, in order to restore it later. + */ + private Map changeContext() { + // We prepare a map to store the context + Map context = new HashMap(); + // For each resource of the model + for (Resource otherResource : this.getResourceSet().getResources()) { + // We must only look at LooseResources + if (otherResource instanceof LooseResource) { + // For each of the objects that the resource contains + for (EObject o : otherResource.getContents()) { + // If the object is readonly, we must handle the fact that + // this object does not consider this resource to be its resource + if (o instanceof InternalEObject + && ((((LooseResource)otherResource).tags.getTagOf(o.eClass()) == ClassTag.COMPLETELY_SHAREABLE))) { + // Then we store its actual resource + context.put(o, o.eResource()); + // And we change it temporarily + ((AbstractShareableEObject)o).setResourceNonInverse((Internal)otherResource); + } + } + } + } + // Finally we return the context, in order to restore it later + return context; + } + + /** + * Restores the context previously saved. + * @param context The context, that is a set of objects and their theoretical resource. + */ + private void restoreContext(Map context) { + for (EObject o : context.keySet()) + ((AbstractShareableEObject)o).setResourceNonInverse((Internal)context.get(o)); + } + + @Override + /** + * Overrides the main save method in order to make the contained + * objects believe that they are in this resource, temporarily. + * TODO other save methods ? + */ + public void save(Map options) throws IOException { + // Save context of all contents + Map context = changeContext(); + + // Do the save + super.save(options); + + // Restore the context of all contents + restoreContext(context); + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/Copy.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/Copy.java new file mode 100644 index 0000000000000000000000000000000000000000..4b58b7fc9fe2005cb4af9bbbc55cbde4d786fcec --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/Copy.java @@ -0,0 +1,230 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.util; + +/* + + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; + +import static java.nio.file.StandardCopyOption.*; + +import java.nio.file.attribute.*; + +import static java.nio.file.FileVisitResult.*; + +import java.io.IOException; +import java.util.*; + +/** + * Sample code that copies files in a similar manner to the cp(1) program. + */ + +public class Copy { + + /** + * Returns {@code true} if okay to overwrite a file ("cp -i") + */ + static boolean okayToOverwrite(Path file) { + String answer = System.console().readLine("overwrite %s (yes/no)? ", file); + return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes")); + } + + /** + * Copy source file to target location. If {@code prompt} is true then prompt user to overwrite target if it exists. + * The {@code preserve} parameter determines if file attributes should be copied/preserved. + */ + static void copyFile(Path source, Path target, boolean prompt, boolean preserve) { + CopyOption[] options = (preserve) ? new CopyOption[] { COPY_ATTRIBUTES, REPLACE_EXISTING } + : new CopyOption[] { REPLACE_EXISTING }; + if (!prompt || Files.notExists(target) || okayToOverwrite(target)) { + try { + Files.copy(source, target, options); + } catch (IOException x) { + System.err.format("Unable to copy: %s: %s%n", source, x); + } + } + } + + /** + * A {@code FileVisitor} that copies a file-tree ("cp -r") + */ + static class TreeCopier implements FileVisitor { + private final Path source; + private final Path target; + private final boolean prompt; + private final boolean preserve; + + TreeCopier(Path source, Path target, boolean prompt, boolean preserve) { + this.source = source; + this.target = target; + this.prompt = prompt; + this.preserve = preserve; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + // before visiting entries in a directory we copy the directory + // (okay if directory already exists). + CopyOption[] options = (preserve) ? new CopyOption[] { COPY_ATTRIBUTES } : new CopyOption[0]; + + Path newdir = target.resolve(source.relativize(dir)); + try { + Files.copy(dir, newdir, options); + } catch (FileAlreadyExistsException x) { + // ignore + } catch (IOException x) { + System.err.format("Unable to create: %s: %s%n", newdir, x); + return SKIP_SUBTREE; + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + copyFile(file, target.resolve(source.relativize(file)), prompt, preserve); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + // fix up modification time of directory when done + if (exc == null && preserve) { + Path newdir = target.resolve(source.relativize(dir)); + try { + FileTime time = Files.getLastModifiedTime(dir); + Files.setLastModifiedTime(newdir, time); + } catch (IOException x) { + System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x); + } + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) { + if (exc instanceof FileSystemLoopException) { + System.err.println("cycle detected: " + file); + } else { + System.err.format("Unable to copy: %s: %s%n", file, exc); + } + return CONTINUE; + } + } + + static void usage() { + System.err.println("java Copy [-ip] source... target"); + System.err.println("java Copy -r [-ip] source-dir... target"); + System.exit(-1); + } + + public static void copyRecursive(Path source, Path dest) throws IOException { + EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); + TreeCopier tc = new TreeCopier(source, dest, false, false); + Files.walkFileTree(source, opts, Integer.MAX_VALUE, tc); + } + + public static void main(String[] args) throws IOException { + boolean recursive = false; + boolean prompt = false; + boolean preserve = false; + + // process options + int argi = 0; + while (argi < args.length) { + String arg = args[argi]; + if (!arg.startsWith("-")) + break; + if (arg.length() < 2) + usage(); + for (int i = 1; i < arg.length(); i++) { + char c = arg.charAt(i); + switch (c) { + case 'r': + recursive = true; + break; + case 'i': + prompt = true; + break; + case 'p': + preserve = true; + break; + default: + usage(); + } + } + argi++; + } + + // remaining arguments are the source files(s) and the target location + int remaining = args.length - argi; + if (remaining < 2) + usage(); + Path[] source = new Path[remaining - 1]; + int i = 0; + while (remaining > 1) { + source[i++] = Paths.get(args[argi++]); + remaining--; + } + Path target = Paths.get(args[argi]); + + // check if target is a directory + boolean isDir = Files.isDirectory(target); + + // copy each source file/directory to target + for (i = 0; i < source.length; i++) { + Path dest = (isDir) ? target.resolve(source[i].getFileName()) : target; + + if (recursive) { + // follow links when copying files + EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); + TreeCopier tc = new TreeCopier(source[i], dest, prompt, preserve); + Files.walkFileTree(source[i], opts, Integer.MAX_VALUE, tc); + } else { + // not recursive so source must not be a directory + if (Files.isDirectory(source[i])) { + System.err.format("%s: is a directory%n", source[i]); + continue; + } + copyFile(source[i], dest, prompt, preserve); + } + } + } +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/EcoreHelper.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/EcoreHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..1f11cb806838c805e3292b6e583ac1033973f123 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/EcoreHelper.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.util; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; + +public class EcoreHelper { + + public static class NoSingleRootException extends Exception { + private static final long serialVersionUID = 1L; + private Set roots; + + public NoSingleRootException(Set foundRoots) { + roots = new HashSet(); + roots.addAll(foundRoots); + } + + @Override + public String getMessage() { + String message = "A single root is required. Roots found: "; + for (EClass aClass : roots) + message += aClass.getName() + ", "; + return message.substring(0, message.length() - 2) + "\n" + super.getMessage(); + } + + } + public static boolean isPropertyDesignedMutable(EStructuralFeature f) { + return f.getName().endsWith("_m"); + } + + + public static Set findRoots(Set metamodel) { + + // Preparing result set + Set roots = new HashSet(); + + // Finding all contained classes + Set containedClasses = new HashSet(); + for (EClass aClass : metamodel) + for (EReference r : aClass.getEAllContainments()) + (containedClasses).add(r.getEReferenceType()); + + // Finding root classes, ie not contained classes + for (EClass aClass : metamodel) + if (!containedClasses.contains(aClass)) + roots.add(aClass); + return roots; + } + + public static EClass findRoot(Set treeMetamodel) throws NoSingleRootException { + return findRoots(treeMetamodel).iterator().next(); + } + + public static EClass findRoot(Resource treeMetamodel) throws NoSingleRootException { + return findRoot(findEClasses(treeMetamodel)); + } + + public static EClass findRoot(ResourceSet treeMetamodel) throws NoSingleRootException { + return findRoot(findEClasses(treeMetamodel)); + } + + public static Set findRoots(ResourceSet treeMetamodel) { + return findRoots(findEClasses(treeMetamodel)); + } + + public static Set findEClasses(ResourceSet metamodel) { + Set classes = new HashSet(); + for (Resource res : metamodel.getResources()) { + classes.addAll(findEClasses(res)); + } + return classes; + } + + public static Set findEClasses(Resource resource) { + Set classes = new HashSet(); + // Getting all the classes from the resource + for (Iterator i = resource.getAllContents(); i.hasNext();) { + EObject next = i.next(); + if (next instanceof EClass) + classes.add((EClass) next); + } + return classes; + } + + public static Set findEPackages(Resource resource) { + Set packages = new HashSet(); + // Getting all the classes from the resource + for (Iterator i = resource.getAllContents(); i.hasNext();) { + EObject next = i.next(); + if (next instanceof EPackage) + packages.add((EPackage) next); + } + return packages; + } + + public static Set findEPackages(ResourceSet metamodel) { + Set packages = new HashSet(); + for (Resource res : metamodel.getResources()) { + packages.addAll(findEPackages(res)); + } + return packages; + } + + public static String computeFullyQualifiedName(EPackage p) { + String result = p.getName(); + + if (p.getESuperPackage() != null) + result = computeFullyQualifiedName(p.getESuperPackage()) + "." + result; + + return result; + } + + public static String computeFullyQualifiedName(EClass c) { + return computeFullyQualifiedName(c.getEPackage())+"."+c.getName(); + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/Log.java b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/Log.java new file mode 100644 index 0000000000000000000000000000000000000000..be44f85c5105cbf7c0ca6fae45ec196f603ed7ac --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/src/fr/inria/diverse/cloning/runtime/util/Log.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.inria.diverse.cloning.runtime.util; + +import java.io.IOException; +import java.io.PrintStream; + +import org.eclipse.ui.console.ConsolePlugin; +import org.eclipse.ui.console.IConsole; +import org.eclipse.ui.console.IConsoleManager; +import org.eclipse.ui.console.MessageConsole; +import org.eclipse.ui.console.MessageConsoleStream; + +public class Log { + private static int level = 0; + private static final String INFO = "INFO."; + private static final String ERROR = "ERROR"; + private static final String DEBUG = "DEBUG"; + private static final String ESCCHAR = "\u001b"; + private static final int GREEN = 32; + // private static final int RED = 31 + private static final int BRIGHTRED = 91; + private static final int RESET = 0; + private static boolean ansiColoring = false; + + private static boolean useProgress = false; + private static int progress = 0; + private static int maxProgress = 0; + + private static MessageConsole console; + + public static void enableAnsiColoring() { + ansiColoring = true; + } + + private static MessageConsole findConsole(String name) { + ConsolePlugin plugin = ConsolePlugin.getDefault(); + IConsoleManager conMan = plugin.getConsoleManager(); + IConsole[] existing = conMan.getConsoles(); + for (int i = 0; i < existing.length; i++) + if (name.equals(existing[i].getName())) + return (MessageConsole) existing[i]; + // no console found, so create a new one + MessageConsole myConsole = new MessageConsole(name, null); + conMan.addConsoles(new IConsole[] { myConsole }); + return myConsole; + } + + public static void enableEclipseConsole(String consoleName) { + if (console == null) + console = findConsole(consoleName); + } + + private static void printlnStream(PrintStream p, String s) { + if (console == null) { + p.println(s); + } else { + MessageConsoleStream consoleStream = console.newMessageStream(); + try { + + consoleStream.println(s); + consoleStream.close(); + + } catch (IOException e) { + // TODO Bloc catch généré automatiquement + e.printStackTrace(); + } + + } + } + + private static void printlnOut(String s) { + printlnStream(System.out, s); + } + + private static void printlnErr(String s) { + printlnStream(System.err, s); + } + + private static String shift() { + String shift = ""; + int i = 0; + while ((i = i + 1) < level) + shift = "| " + shift; + return shift; + } + + private static String color(String str, int color) { + if (ansiColoring) { + return ESCCHAR + "[" + color + "m" + str + ESCCHAR + "[" + RESET + "m"; + } else + return str; + } + + private static String formatMessage(String type, String msg) { + return "[" + type + "] " + shift() + msg; + } + + public static void info(String msg) { + if (useProgress) + printlnOut(formatMessage(INFO + computeProgress(), msg)); + else + printlnOut(formatMessage(INFO, msg)); + } + + public static void debug(String msg) { + printlnOut(color(formatMessage(DEBUG, msg), GREEN)); + } + + public static void error(String msg) { + printlnErr(color(formatMessage(ERROR, msg), BRIGHTRED)); + } + + public static void plusLevel() { + level = level + 1; + } + + public static void minusLevel() { + level = level - 1; + } + + private static String computeProgress() { + double ratio = ((double) progress) / ((double) maxProgress); + return String.valueOf(String.format("%03d", (int) (ratio * 100))) + "%"; + } + + public static void enableProgress(int maxValue) { + useProgress = true; + progress = 0; + maxProgress = maxValue; + } + + public static void disableProgress() { + useProgress = false; + } + + public static void incProgress() { + progress++; + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/trashbin/DeepCloner.java b/moclodash/fr.inria.diverse.cloning.runtime/trashbin/DeepCloner.java new file mode 100644 index 0000000000000000000000000000000000000000..98f9675d7db4e0b44c83190d5fa5de20e2ed7938 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/trashbin/DeepCloner.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.diverse.fancyemfcloning.cloner.impl; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +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.EcoreUtil; + +import fr.diverse.fancyemfcloning.cloner.Cloner; +import fr.diverse.fancyemfcloning.customemf.ClassTag; + +public class DeepCloner implements Cloner { + + @Override + public ResourceSet clone(ResourceSet cloned, String folder) { + + // Creating empty clone resource set + ResourceSet clone = new ResourceSetImpl(); + + // Preparing the copier, which will allow us to copy objects in new + // resources AND to resolve the references in the clone (even between resources) + EcoreUtil.Copier copier = new EcoreUtil.Copier(); + + // Cloning all resources + for (Resource r : cloned.getResources()) { + // Getting the complete file name + String filename = r.getURI().segmentsList().get(r.getURI().segmentsList().size() - 1); + // Preparing the URI of the new resource (with a specific 'folder') + URI uri = r.getURI().trimSegments(1).appendSegment(folder).appendSegment(filename); + // Creating the new Resource + Resource resourceClone = clone.createResource(uri); + // Copying objects (but not the references) + resourceClone.getContents().addAll(copier.copyAll(r.getContents())); + } + + // Resolving references (all of them, even between resources of the clone) + copier.copyReferences(); + + // Returning the obtained clone + return clone; + } + + @Override + public ClassTag getTagOf(EClass c) { + return ClassTag.completelyMutable; + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/trashbin/MutClassesOnlyCloner.java b/moclodash/fr.inria.diverse.cloning.runtime/trashbin/MutClassesOnlyCloner.java new file mode 100644 index 0000000000000000000000000000000000000000..c26c9596542e9492a791ec6db0c0726de8e0979e --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/trashbin/MutClassesOnlyCloner.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.diverse.fancyemfcloning.cloner.impl; + +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +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.EcoreUtil; + +import test.LooseCopier; +import test.LooseResource; +import fr.diverse.fancyemfcloning.cloner.Cloner; +import fr.diverse.fancyemfcloning.customemf.ClassTag; +import fr.diverse.fancyemfcloning.tagger.AbstractMetamodelTagger; +import fr.diverse.fancyemfcloning.tagger.MutClassesOnlyMetamodelTagger; + +public class MutClassesOnlyCloner implements Cloner { + + protected AbstractMetamodelTagger tagger; + + protected MutClassesOnlyCloner() { + } + + public MutClassesOnlyCloner(Set metamodel) { + this(); + this.tagger = new MutClassesOnlyMetamodelTagger(metamodel); + } + + @Override + public ResourceSet clone(ResourceSet cloned, String folder) { + + // Creating empty clone resource set + ResourceSet clone = new ResourceSetImpl(); + + // Preparing the copier, which will allow us to copy objects in new + // resources + // AND to resolve the references in the clone (even between resources) + EcoreUtil.Copier copier = new LooseCopier();// new EcoreUtil.Copier(); + + // Cloning all resources + for (Resource r : cloned.getResources()) { + // Getting the complete file name + String filename = r.getURI().segmentsList().get(r.getURI().segmentsList().size() - 1); + // Preparing the URI of the new resource (with a specific 'folder') + URI uri = r.getURI().trimSegments(1).appendSegment(folder).appendSegment(filename); + // Creating the new Resource (Loose, because objects might be + // shared) + Resource resourceClone = new LooseResource(this); + resourceClone.setURI(uri); + clone.getResources().add(resourceClone); + // Copying objects (but not the references, and only mutable ones) + // OLD for (EObject o : r.getContents()) { + for (Iterator i = r.getAllContents(); i.hasNext();) { + EObject o = i.next(); + ClassTag mutability = tagger.getTagOfEClass(o.eClass()); + if (mutability == ClassTag.canReachMutable || mutability == ClassTag.completelyMutable + || mutability == ClassTag.partiallyMutable) { + resourceClone.getContents().add(copier.copy(o)); + } else { + resourceClone.getContents().add(o); + } + + } + } + + // Resolving references (all of them, even between resources of the clone) + copier.copyReferences(); + + // Returning the obtained clone + return clone; + } + + @Override + public ClassTag getTagOf(EClass c) { + return tagger.getTagOfEClass(c); + } + +} diff --git a/moclodash/fr.inria.diverse.cloning.runtime/trashbin/WeakMutClassesOnlyCloner.java b/moclodash/fr.inria.diverse.cloning.runtime/trashbin/WeakMutClassesOnlyCloner.java new file mode 100644 index 0000000000000000000000000000000000000000..36dcc688ac9df9bdf5e2f8343f89e34ad43efc62 --- /dev/null +++ b/moclodash/fr.inria.diverse.cloning.runtime/trashbin/WeakMutClassesOnlyCloner.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2014 Université de Rennes 1. + * 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: + * Erwan Bousse - initial API and implementation + ******************************************************************************/ +package fr.diverse.fancyemfcloning.cloner.impl; + +import java.util.Set; + +import org.eclipse.emf.ecore.resource.Resource; + +import fr.diverse.fancyemfcloning.tagger.WeakMutClassesOnlyMetamodelTagger; + +public class WeakMutClassesOnlyCloner extends MutClassesOnlyCloner{ + + + public WeakMutClassesOnlyCloner(Set metamodel) { + super(); + this.tagger = new WeakMutClassesOnlyMetamodelTagger(metamodel); + } + +}