-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ScopedContentAdapter behaves like a normal EMF content adapter, but only listen to changes in an explicit set of types. It relies on a static analysis of all the types it can encounter to avoid installing itself greedily in parts of the model where it can safely determine that no instance of the types in its scope can be found. Change-Id: I71d96ed8f2ec4118eca60075b128749990c2b887
- Loading branch information
Showing
12 changed files
with
828 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
...g.eclipse.sirius.ext.emf/src/org/eclipse/sirius/ext/emf/adapter/ScopedContentAdapter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package org.eclipse.sirius.ext.emf.adapter; | ||
|
||
// CHECKSTYLE:OFF | ||
import java.util.Arrays; | ||
import java.util.Iterator; | ||
import java.util.Set; | ||
|
||
import org.eclipse.emf.common.notify.Notifier; | ||
import org.eclipse.emf.ecore.EClass; | ||
import org.eclipse.emf.ecore.EObject; | ||
import org.eclipse.emf.ecore.util.EContentAdapter; | ||
import org.eclipse.emf.ecore.util.InternalEList; | ||
|
||
import com.google.common.base.Preconditions; | ||
import com.google.common.collect.ImmutableSet; | ||
import com.google.common.collect.Sets; | ||
|
||
/** | ||
* A content adapter which is only interested in some types of EObjects, and | ||
* avoids installing itself in parts of the model where it can determine | ||
* statically that no instance of these interesting types can appear. | ||
* | ||
* @author pcdavid | ||
*/ | ||
public class ScopedContentAdapter extends EContentAdapter { | ||
private final Set<EClass> scope; | ||
|
||
private final TypesAnalyzer analyzer; | ||
|
||
public ScopedContentAdapter(TypesAnalyzer analyzer, EClass... scope) { | ||
this(analyzer, Arrays.asList(scope)); | ||
} | ||
|
||
public ScopedContentAdapter(TypesAnalyzer analyzer, Iterable<EClass> scope) { | ||
this.analyzer = Preconditions.checkNotNull(analyzer); | ||
this.scope = ImmutableSet.copyOf(Preconditions.checkNotNull(scope)); | ||
} | ||
|
||
@Override | ||
protected void setTarget(EObject target) { | ||
basicSetTarget(target); | ||
for (Iterator<? extends Notifier> i = resolve() ? target.eContents().iterator() : ((InternalEList<? extends Notifier>) target.eContents()).basicIterator(); i.hasNext();) { | ||
Notifier notifier = i.next(); | ||
if (notifier instanceof EObject) { | ||
if (inScope((EObject) notifier)) { | ||
addAdapter(notifier); | ||
} | ||
} else { | ||
addAdapter(notifier); | ||
} | ||
} | ||
} | ||
|
||
private boolean inScope(EObject target) { | ||
EClass targetType = target.eClass(); | ||
if (scope.contains(targetType)) { | ||
return true; | ||
} else { | ||
for (EClass k : scope) { | ||
if (analyzer.canContain(targetType, k)) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
} |
176 changes: 176 additions & 0 deletions
176
plugins/org.eclipse.sirius.ext.emf/src/org/eclipse/sirius/ext/emf/adapter/TypesAnalyzer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package org.eclipse.sirius.ext.emf.adapter; | ||
|
||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.Set; | ||
|
||
import org.eclipse.emf.ecore.EClass; | ||
import org.eclipse.emf.ecore.EPackage; | ||
import org.eclipse.emf.ecore.EReference; | ||
import org.eclipse.sirius.ext.base.relations.Relation; | ||
import org.eclipse.sirius.ext.base.relations.TransitiveClosure; | ||
|
||
import com.google.common.collect.HashMultimap; | ||
import com.google.common.collect.ImmutableMultimap; | ||
import com.google.common.collect.ImmutableSet; | ||
import com.google.common.collect.Iterables; | ||
import com.google.common.collect.LinkedHashMultimap; | ||
import com.google.common.collect.Lists; | ||
import com.google.common.collect.Multimap; | ||
|
||
// CHECKSTYLE:OFF | ||
/** | ||
* Provides useful static analysis on a set of EMF types (EClasses). | ||
* | ||
* @author pcdavid | ||
*/ | ||
public final class TypesAnalyzer { | ||
/** | ||
* All the packages considered. This does does includes their sub-packages, | ||
* if any. They must be included explicitly if needed. | ||
*/ | ||
private final ImmutableSet<EPackage> packages; | ||
|
||
/** | ||
* All the classes in all the packages considered. | ||
*/ | ||
private final ImmutableSet<EClass> classes; | ||
|
||
/** | ||
* The reflective transitive closure of the relation "x extends y". In other | ||
* words, the map contains the pair (x, y) if and only if x == y or y is a | ||
* direct or indirect super-type of x. | ||
*/ | ||
private final ImmutableMultimap<EClass, EClass> superTypesOf; | ||
|
||
/** | ||
* The reflective transitive closure of the relation "y extends x". In other | ||
* words, the map contains the pair (x, y) if and only if x == y or x is a | ||
* direct or indirect super-type of y. | ||
*/ | ||
private final ImmutableMultimap<EClass, EClass> subTypesOf; | ||
|
||
private final Multimap<EClass, EClass> containement; | ||
|
||
private TypesAnalyzer(Iterable<EPackage> packages) { | ||
this.packages = ImmutableSet.copyOf(packages); | ||
this.classes = getAllEClasses(this.packages); | ||
this.superTypesOf = computeSuperTypes(); | ||
this.subTypesOf = this.superTypesOf.inverse(); | ||
this.containement = computeContainments(); | ||
} | ||
|
||
/** | ||
* Helper method to compute all the direct and indirect sub-packages of a | ||
* set of root packages. | ||
* | ||
* @param roots | ||
* the root packages to consider. | ||
* @return the set of all root packages and all their directly and | ||
* indirectly contained sub-packages. | ||
*/ | ||
public static Set<EPackage> withDescendants(Iterable<EPackage> roots) { | ||
Collection<EPackage> result = Lists.newArrayList(); | ||
for (EPackage root : roots) { | ||
result.add(root); | ||
result.addAll(withDescendants(root.getESubpackages())); | ||
} | ||
return ImmutableSet.copyOf(result); | ||
} | ||
|
||
/** | ||
* Returns an analyzer for all the types in the specified package (not | ||
* including any sub-package). | ||
* | ||
* @param pkg | ||
* the package to analyze. | ||
* @return an analyzer aware of all the types in the specified package. | ||
*/ | ||
public static TypesAnalyzer on(EPackage pkg) { | ||
return TypesAnalyzer.on(Collections.singleton(pkg)); | ||
} | ||
|
||
public static TypesAnalyzer on(Iterable<EPackage> pkgs) { | ||
return new TypesAnalyzer(pkgs); | ||
} | ||
|
||
public static TypesAnalyzer on(EPackage.Registry reg) { | ||
return TypesAnalyzer.on(Iterables.filter(reg.values(), EPackage.class)); | ||
} | ||
|
||
public ImmutableSet<EPackage> getScope() { | ||
return packages; | ||
} | ||
|
||
public ImmutableSet<EClass> getAllSubTypes(EClass type) { | ||
return ImmutableSet.copyOf(subTypesOf.get(type)); | ||
} | ||
|
||
public boolean isSuperTypeOf(EClass superType, EClass subType) { | ||
return subTypesOf.containsEntry(superType, subType); | ||
} | ||
|
||
public boolean isSubTypeOf(EClass subType, EClass superType) { | ||
return superTypesOf.containsEntry(subType, superType); | ||
} | ||
|
||
public boolean canContain(EClass container, EClass contained) { | ||
return containement.containsEntry(container, contained); | ||
} | ||
|
||
private ImmutableSet<EClass> getAllEClasses(Set<EPackage> pkgs) { | ||
Collection<EClass> result = Lists.newArrayList(); | ||
for (EPackage ePackage : pkgs) { | ||
Iterables.addAll(result, Iterables.filter(ePackage.getEClassifiers(), EClass.class)); | ||
} | ||
return ImmutableSet.copyOf(result); | ||
} | ||
|
||
private ImmutableMultimap<EClass, EClass> computeSuperTypes() { | ||
Multimap<EClass, EClass> result = LinkedHashMultimap.create(); | ||
for (EClass k : classes) { | ||
result.put(k, k); | ||
result.putAll(k, k.getEAllSuperTypes()); | ||
} | ||
return ImmutableMultimap.copyOf(result); | ||
} | ||
|
||
private Multimap<EClass, EClass> computeContainments() { | ||
final Multimap<EClass, EClass> directlyContains = HashMultimap.create(); | ||
for (EClass container : classes) { | ||
directlyContains.putAll(container, getPossiblyContainedTypes(container)); | ||
} | ||
Multimap<EClass, EClass> containment = HashMultimap.create(); | ||
Relation<EClass> containmentRel = new TransitiveClosure<EClass>(new Relation<EClass>() { | ||
@Override | ||
public Set<EClass> apply(EClass container) { | ||
return ImmutableSet.copyOf(directlyContains.get(container)); | ||
} | ||
}); | ||
for (EClass container : classes) { | ||
containment.putAll(container, containmentRel.apply(container)); | ||
} | ||
return containment; | ||
} | ||
|
||
private Set<EClass> getPossiblyContainedTypes(EClass container) { | ||
Collection<EClass> result = Lists.newArrayList(); | ||
for (EClass actualContainerType : subTypesOf.get(container)) { | ||
Set<EReference> containment = getContainmentReferences(actualContainerType); | ||
for (EReference ref : containment) { | ||
result.addAll(subTypesOf.get(ref.getEReferenceType())); | ||
} | ||
} | ||
return ImmutableSet.copyOf(result); | ||
} | ||
|
||
private Set<EReference> getContainmentReferences(EClass actualContainerType) { | ||
Collection<EReference> refs = Lists.newArrayList(); | ||
for (EReference ref : actualContainerType.getEReferences()) { | ||
if (ref.isContainment()) { | ||
refs.add(ref); | ||
} | ||
} | ||
return ImmutableSet.copyOf(refs); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<classpath> | ||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> | ||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> | ||
<classpathentry kind="src" path="src"/> | ||
<classpathentry kind="output" path="bin"/> | ||
</classpath> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<projectDescription> | ||
<name>org.eclipse.sirius.tests.core</name> | ||
<comment></comment> | ||
<projects> | ||
</projects> | ||
<buildSpec> | ||
<buildCommand> | ||
<name>org.eclipse.jdt.core.javabuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
<buildCommand> | ||
<name>org.eclipse.pde.ManifestBuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
<buildCommand> | ||
<name>org.eclipse.pde.SchemaBuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>org.eclipse.pde.PluginNature</nature> | ||
<nature>org.eclipse.jdt.core.javanature</nature> | ||
</natures> | ||
</projectDescription> |
7 changes: 7 additions & 0 deletions
7
plugins/org.eclipse.sirius.tests.core/.settings/org.eclipse.jdt.core.prefs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
eclipse.preferences.version=1 | ||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled | ||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 | ||
org.eclipse.jdt.core.compiler.compliance=1.6 | ||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error | ||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error | ||
org.eclipse.jdt.core.compiler.source=1.6 |
18 changes: 18 additions & 0 deletions
18
plugins/org.eclipse.sirius.tests.core/META-INF/MANIFEST.MF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Manifest-Version: 1.0 | ||
Bundle-ManifestVersion: 2 | ||
Bundle-Name: Sirius Tests | ||
Bundle-SymbolicName: org.eclipse.sirius.tests.core | ||
Bundle-Version: 1.0.0.qualifier | ||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6 | ||
Require-Bundle: org.junit;bundle-version="4.11.0", | ||
com.google.guava;bundle-version="11.0.2", | ||
org.eclipse.sirius.ext.emf;bundle-version="1.0.0", | ||
org.eclipse.sirius;bundle-version="1.0.0", | ||
org.eclipse.sirius.diagram;bundle-version="1.0.0", | ||
org.eclipse.sirius.ui;bundle-version="1.0.0", | ||
org.eclipse.emf.ecore.xmi;bundle-version="2.8.0", | ||
org.hamcrest.library;bundle-version="1.3.0", | ||
org.eclipse.core.runtime;bundle-version="3.8.0", | ||
org.eclipse.sirius.diagram.ui;bundle-version="1.0.0", | ||
org.eclipse.gmf.runtime.notation;bundle-version="1.7.0", | ||
org.eclipse.gmf.runtime.emf.core;bundle-version="1.7.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
source.. = src/ | ||
output.. = bin/ | ||
bin.includes = META-INF/,\ | ||
. |
Oops, something went wrong.