diff options
author | Kristóf Marussy <marussy@mit.bme.hu> | 2020-06-30 18:03:48 +0200 |
---|---|---|
committer | Kristóf Marussy <marussy@mit.bme.hu> | 2020-06-30 18:03:48 +0200 |
commit | e11bce7ad3e803e80883499fec0ad6e4540ffe43 (patch) | |
tree | ca3ad9d5b9137e9455485e43350a4a353f487f22 /Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java | |
parent | Disable unrepairable match scoping for now (diff) | |
download | VIATRA-Generator-e11bce7ad3e803e80883499fec0ad6e4540ffe43.tar.gz VIATRA-Generator-e11bce7ad3e803e80883499fec0ad6e4540ffe43.tar.zst VIATRA-Generator-e11bce7ad3e803e80883499fec0ad6e4540ffe43.zip |
Add modified VIATRA-DSE version
Diffstat (limited to 'Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java')
-rw-r--r-- | Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java new file mode 100644 index 00000000..14b3acfb --- /dev/null +++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/util/EMFHelper.java | |||
@@ -0,0 +1,424 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package org.eclipse.viatra.dse.util; | ||
10 | |||
11 | import java.io.IOException; | ||
12 | import java.util.Collections; | ||
13 | import java.util.Comparator; | ||
14 | import java.util.HashMap; | ||
15 | import java.util.HashSet; | ||
16 | import java.util.List; | ||
17 | import java.util.Map; | ||
18 | import java.util.Objects; | ||
19 | import java.util.Set; | ||
20 | import java.util.TreeSet; | ||
21 | |||
22 | import org.apache.log4j.Logger; | ||
23 | import org.eclipse.emf.common.command.BasicCommandStack; | ||
24 | import org.eclipse.emf.common.notify.Notifier; | ||
25 | import org.eclipse.emf.common.util.EList; | ||
26 | import org.eclipse.emf.common.util.URI; | ||
27 | import org.eclipse.emf.ecore.EAttribute; | ||
28 | import org.eclipse.emf.ecore.EClass; | ||
29 | import org.eclipse.emf.ecore.EClassifier; | ||
30 | import org.eclipse.emf.ecore.ENamedElement; | ||
31 | import org.eclipse.emf.ecore.EObject; | ||
32 | import org.eclipse.emf.ecore.EPackage; | ||
33 | import org.eclipse.emf.ecore.EReference; | ||
34 | import org.eclipse.emf.ecore.resource.Resource; | ||
35 | import org.eclipse.emf.ecore.resource.ResourceSet; | ||
36 | import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; | ||
37 | import org.eclipse.emf.ecore.util.EcoreUtil.Copier; | ||
38 | import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; | ||
39 | import org.eclipse.emf.edit.command.AddCommand; | ||
40 | import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; | ||
41 | import org.eclipse.emf.edit.domain.EditingDomain; | ||
42 | import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; | ||
43 | |||
44 | /** | ||
45 | * This class contains static helper methods. | ||
46 | * @author Andras Szabolcs Nagy | ||
47 | */ | ||
48 | public final class EMFHelper { | ||
49 | |||
50 | private static final Logger logger = Logger.getLogger(EMFHelper.class); | ||
51 | |||
52 | private EMFHelper() { | ||
53 | } | ||
54 | |||
55 | public static class EmfHelperException extends RuntimeException { | ||
56 | private static final long serialVersionUID = 7635796550669616626L; | ||
57 | |||
58 | public EmfHelperException(String string) { | ||
59 | super(string); | ||
60 | } | ||
61 | public EmfHelperException(String string, Throwable e) { | ||
62 | super(string, e); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Gets the {@link EditingDomain} of either an {@link EObject}, {@link Resource} or {@link ResourceSet}. | ||
68 | * @param notifier The {@link Notifier}. | ||
69 | * @return The EditingDomain. | ||
70 | */ | ||
71 | public static EditingDomain getEditingDomain(Notifier notifier) { | ||
72 | Objects.requireNonNull(notifier); | ||
73 | if (notifier instanceof EObject) { | ||
74 | EObject eObject = (EObject) notifier; | ||
75 | return AdapterFactoryEditingDomain.getEditingDomainFor(eObject); | ||
76 | } else if (notifier instanceof Resource) { | ||
77 | Resource resource = (Resource) notifier; | ||
78 | EList<EObject> contents = resource.getContents(); | ||
79 | if (contents.isEmpty()) { | ||
80 | return null; | ||
81 | } | ||
82 | return AdapterFactoryEditingDomain.getEditingDomainFor(contents.get(0)); | ||
83 | } else if (notifier instanceof ResourceSet) { | ||
84 | ResourceSet resourceSet = (ResourceSet) notifier; | ||
85 | if (resourceSet.getResources().isEmpty()) { | ||
86 | return null; | ||
87 | } | ||
88 | return getEditingDomain(resourceSet.getResources().get(0)); | ||
89 | } | ||
90 | |||
91 | return null; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Creates (or gets if already exists) an {@link EditingDomain} over the given {@link Notifier}, | ||
96 | * either an {@link EObject}, {@link Resource} or {@link ResourceSet}. | ||
97 | * @param notifier The {@link Notifier}. | ||
98 | * @return The EditingDomain. | ||
99 | */ | ||
100 | public static EditingDomain createEditingDomain(Notifier notifier) { | ||
101 | |||
102 | EditingDomain domain = getEditingDomain(notifier); | ||
103 | if (domain != null) { | ||
104 | return domain; | ||
105 | } | ||
106 | |||
107 | registerExtensionForXmiSerializer("dummyext"); | ||
108 | |||
109 | if (notifier instanceof EObject) { | ||
110 | EObject eObject = (EObject) notifier; | ||
111 | |||
112 | domain = new AdapterFactoryEditingDomain(null, new BasicCommandStack()); | ||
113 | Resource resource = domain.getResourceSet().createResource(URI.createFileURI("dummy.dummyext")); | ||
114 | domain.getCommandStack().execute(new AddCommand(domain, resource.getContents(), eObject)); | ||
115 | |||
116 | return domain; | ||
117 | |||
118 | } else if (notifier instanceof Resource) { | ||
119 | Resource resource = (Resource) notifier; | ||
120 | |||
121 | ResourceSet resourceSet = resource.getResourceSet(); | ||
122 | if (resourceSet != null) { | ||
123 | return new AdapterFactoryEditingDomain(null, new BasicCommandStack(), resourceSet); | ||
124 | } else { | ||
125 | domain = new AdapterFactoryEditingDomain(null, new BasicCommandStack(), (ResourceSet) null); | ||
126 | resourceSet = domain.getResourceSet(); | ||
127 | domain.getCommandStack().execute(new AddCommand(domain, resourceSet.getResources(), resource)); | ||
128 | return domain; | ||
129 | } | ||
130 | |||
131 | } else if (notifier instanceof ResourceSet) { | ||
132 | return new AdapterFactoryEditingDomain(null, new BasicCommandStack(), (ResourceSet) notifier); | ||
133 | } else { | ||
134 | throw new EmfHelperException("Not supported argument type."); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Saves the EMF model (EObject or Resource) into the given file. An {@link XMIResourceFactoryImpl} will be | ||
140 | * registered if not already. | ||
141 | * | ||
142 | * Doesn't throw exception but logs an error if the save was unsuccessful. | ||
143 | * | ||
144 | * @param model Can be an {@link EObject} or a {@link Resource}. | ||
145 | * @param fileName | ||
146 | */ | ||
147 | public static void saveModel(Notifier model, String fileName) { | ||
148 | |||
149 | Objects.requireNonNull(model); | ||
150 | Preconditions.checkArgument(fileName != null && !fileName.isEmpty(), "File name is null or empty."); | ||
151 | |||
152 | int extensionIndex = fileName.lastIndexOf('.'); | ||
153 | |||
154 | Preconditions.checkState(extensionIndex > -1 && extensionIndex != fileName.length() - 1, "Bad file extension."); | ||
155 | |||
156 | String ext = fileName.substring(extensionIndex + 1); | ||
157 | |||
158 | registerExtensionForXmiSerializer(ext); | ||
159 | |||
160 | URI uri = URI.createFileURI(fileName); | ||
161 | Resource resource; | ||
162 | |||
163 | if (model instanceof ResourceSet) { | ||
164 | throw new EmfHelperException("Unsupported type: ResourceSet"); | ||
165 | } else if (model instanceof Resource) { | ||
166 | resource = (Resource) model; | ||
167 | } else if (model instanceof EObject) { | ||
168 | EObject root = (EObject) model; | ||
169 | ResourceSet resSet = new ResourceSetImpl(); | ||
170 | resource = resSet.createResource(uri); | ||
171 | resource.getContents().add(root); | ||
172 | } else { | ||
173 | throw new EmfHelperException("Unkown type: " + model.getClass()); | ||
174 | } | ||
175 | |||
176 | resource.setURI(uri); | ||
177 | saveResource(resource); | ||
178 | } | ||
179 | |||
180 | private static void saveResource(Resource resource) { | ||
181 | try { | ||
182 | resource.save(Collections.emptyMap()); | ||
183 | } catch (IOException e) { | ||
184 | logger.error(e); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * Loads a model as a {@link Resource}. In headless mode, don't forget to call XYZPackage.eINSTANCE. | ||
190 | */ | ||
191 | public static Resource loadModel(String fileName) throws IOException { | ||
192 | Preconditions.checkArgument(fileName != null && !fileName.isEmpty(), "File name is null or empty."); | ||
193 | int extensionIndex = fileName.lastIndexOf('.'); | ||
194 | Preconditions.checkState(extensionIndex > -1 && extensionIndex != fileName.length() - 1, "Bad file extension."); | ||
195 | |||
196 | String ext = fileName.substring(extensionIndex + 1); | ||
197 | registerExtensionForXmiSerializer(ext); | ||
198 | |||
199 | ResourceSetImpl rSet = new ResourceSetImpl(); | ||
200 | URI fileUri = URI.createFileURI(fileName); | ||
201 | Resource resource = rSet.createResource(fileUri); | ||
202 | |||
203 | resource.load(null); | ||
204 | return resource; | ||
205 | } | ||
206 | |||
207 | /** | ||
208 | * Retrieves the root EObject from a Resource or ResourceSet. | ||
209 | * <ul> | ||
210 | * <li>Returns null if there is no content.</li> | ||
211 | * <li>Returns the notifier itself if it is an EObject.</li> | ||
212 | * <li>Logs a warn if there are multiple roots.</li> | ||
213 | * </ul> | ||
214 | * | ||
215 | * @param notifier | ||
216 | * @return The root EObject or null. | ||
217 | */ | ||
218 | public static EObject getRootEObject(Notifier notifier) { | ||
219 | if (notifier instanceof EObject) { | ||
220 | return (EObject) notifier; | ||
221 | } else if (notifier instanceof Resource) { | ||
222 | Resource resource = (Resource) notifier; | ||
223 | List<EObject> contents = resource.getContents(); | ||
224 | if (contents.size() > 1) { | ||
225 | logger.warn("Resource has more than one root."); | ||
226 | } | ||
227 | if (contents.isEmpty()) { | ||
228 | return null; | ||
229 | } else { | ||
230 | return contents.get(0); | ||
231 | } | ||
232 | } else if (notifier instanceof ResourceSet) { | ||
233 | ResourceSet resourceSet = (ResourceSet) notifier; | ||
234 | List<Resource> resources = resourceSet.getResources(); | ||
235 | if (resources.size() > 1) { | ||
236 | logger.warn("ResourceSet has more than one resources."); | ||
237 | } | ||
238 | if (resources.isEmpty()) { | ||
239 | return null; | ||
240 | } else { | ||
241 | return getRootEObject(resources.get(0)); | ||
242 | } | ||
243 | } else { | ||
244 | throw new EmfHelperException("Unkown type: " + notifier.getClass()); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * Registers an {@link XMIResourceFactoryImpl} for the given extension. | ||
250 | * @param ext The extension as a String. | ||
251 | */ | ||
252 | public static void registerExtensionForXmiSerializer(String ext) { | ||
253 | Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE; | ||
254 | Map<String, Object> m = reg.getExtensionToFactoryMap(); | ||
255 | m.computeIfAbsent(ext, e -> new XMIResourceFactoryImpl()); | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * Clones the given model. Either an {@link EObject}, {@link Resource} or {@link ResourceSet}. | ||
260 | * @param notifier The root container of the model. | ||
261 | * @return The cloned model. | ||
262 | */ | ||
263 | public static Notifier clone(Notifier notifier) { | ||
264 | Copier copier = new Copier(); | ||
265 | Notifier clonedModel = clone(notifier, copier, null); | ||
266 | copier.copyReferences(); | ||
267 | return clonedModel; | ||
268 | } | ||
269 | |||
270 | private static Notifier clone(Notifier notifier, Copier copier, ResourceSet resourceSetToCloneTo) { | ||
271 | Objects.requireNonNull(copier); | ||
272 | |||
273 | if (notifier instanceof EObject) { | ||
274 | EObject eObject = (EObject) notifier; | ||
275 | return copier.copy(eObject); | ||
276 | } else if (notifier instanceof Resource) { | ||
277 | Resource resource = (Resource) notifier; | ||
278 | ResourceSet rSetTemp = resourceSetToCloneTo; | ||
279 | if (resourceSetToCloneTo == null) { | ||
280 | rSetTemp = new ResourceSetImpl(); | ||
281 | } | ||
282 | Resource clonedResource = rSetTemp.createResource(URI.createFileURI("dummy.dummyext")); | ||
283 | |||
284 | for (EObject eObject : resource.getContents()) { | ||
285 | EObject clonedEObject = copier.copy(eObject); | ||
286 | clonedResource.getContents().add(clonedEObject); | ||
287 | } | ||
288 | |||
289 | return clonedResource; | ||
290 | } else if (notifier instanceof ResourceSet) { | ||
291 | ResourceSet resourceSet = (ResourceSet) notifier; | ||
292 | ResourceSetImpl clonedResourceSet = new ResourceSetImpl(); | ||
293 | |||
294 | for (Resource resource : resourceSet.getResources()) { | ||
295 | clone(resource, copier, clonedResourceSet); | ||
296 | } | ||
297 | |||
298 | return clonedResourceSet; | ||
299 | } else { | ||
300 | throw new EmfHelperException("Not supported argument type."); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | public static class ENamedElementComparator implements Comparator<ENamedElement> { | ||
305 | @Override | ||
306 | public int compare(ENamedElement eClass1, ENamedElement eClass2) { | ||
307 | return eClass1.getName().compareTo(eClass2.getName()); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * This class is used to store | ||
313 | * <ul> | ||
314 | * <li>{@link EClass}es,</li> | ||
315 | * <li>{@link EAttribute}s,</li> | ||
316 | * <li>{@link EReference}s,</li> | ||
317 | * <li>EAttributes by EClasses,</li> | ||
318 | * <li>EReferences by EClasses</li> | ||
319 | * </ul> | ||
320 | * for a given set of {@link EPackage}s. | ||
321 | * | ||
322 | */ | ||
323 | public static class MetaModelElements { | ||
324 | public Set<EPackage> metaModelPackages; | ||
325 | public Set<EClass> classes; | ||
326 | public Set<EAttribute> attributes; | ||
327 | public Set<EReference> references; | ||
328 | public Map<EClass, Set<EAttribute>> attributesOfClass; | ||
329 | public Map<EClass, Set<EReference>> referencesOfClass; | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * Traverses the full metamodel on the given {@link EPackage}s and returns all the classes, attributes and | ||
334 | * references it contains. | ||
335 | * | ||
336 | * @param metaModelPackages | ||
337 | * The set of {@link EPackage}s. | ||
338 | * @return A {@link MetaModelElements} instance containing the metamodel elements. | ||
339 | */ | ||
340 | public static MetaModelElements getAllMetaModelElements(Set<EPackage> metaModelPackages) { | ||
341 | return getMetaModelElements(metaModelPackages, true, true, true); | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * Return a {@link MetaModelElements} instance populated with its {@link MetaModelElements#classes}. | ||
346 | * | ||
347 | * @param metaModelPackages | ||
348 | * The set of {@link EPackage}s. | ||
349 | * @return AA {@link MetaModelElements} instance. | ||
350 | */ | ||
351 | public static MetaModelElements getClasses(Set<EPackage> metaModelPackages) { | ||
352 | return getMetaModelElements(metaModelPackages, true, false, false); | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * Return a {@link MetaModelElements} instance populated with its {@link MetaModelElements#references} and | ||
357 | * {@link MetaModelElements#referencesOfClass}. | ||
358 | * | ||
359 | * @param metaModelPackages | ||
360 | * The set of {@link EPackage}s. | ||
361 | * @return AA {@link MetaModelElements} instance. | ||
362 | */ | ||
363 | public static MetaModelElements getReferences(Set<EPackage> metaModelPackages) { | ||
364 | return getMetaModelElements(metaModelPackages, false, true, false); | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * Return a {@link MetaModelElements} instance populated with its {@link MetaModelElements#attributes} and | ||
369 | * {@link MetaModelElements#attributesOfClass}. | ||
370 | * | ||
371 | * @param metaModelPackages | ||
372 | * The set of {@link EPackage}s. | ||
373 | * @return AA {@link MetaModelElements} instance. | ||
374 | */ | ||
375 | public static MetaModelElements getAttrbiutes(Set<EPackage> metaModelPackages) { | ||
376 | return getMetaModelElements(metaModelPackages, false, false, true); | ||
377 | } | ||
378 | |||
379 | private static MetaModelElements getMetaModelElements(Set<EPackage> metaModelPackages, boolean getClasses, | ||
380 | boolean getReferences, boolean getAttrbiutes) { | ||
381 | |||
382 | Comparator<ENamedElement> comparator = new ENamedElementComparator(); | ||
383 | |||
384 | MetaModelElements result = new MetaModelElements(); | ||
385 | result.metaModelPackages = metaModelPackages; | ||
386 | if (getClasses) { | ||
387 | result.classes = new TreeSet<EClass>(comparator); | ||
388 | } | ||
389 | if (getReferences) { | ||
390 | result.references = new HashSet<EReference>(); | ||
391 | result.referencesOfClass = new HashMap<EClass, Set<EReference>>(); | ||
392 | } | ||
393 | if (getAttrbiutes) { | ||
394 | result.attributes = new HashSet<EAttribute>(); | ||
395 | result.attributesOfClass = new HashMap<EClass, Set<EAttribute>>(); | ||
396 | } | ||
397 | for (EPackage ePackage : metaModelPackages) { | ||
398 | for (EClassifier eClassifier : ePackage.getEClassifiers()) { | ||
399 | if (eClassifier instanceof EClass) { | ||
400 | EClass eClass = ((EClass) eClassifier); | ||
401 | if (getClasses) { | ||
402 | result.classes.add(eClass); | ||
403 | } | ||
404 | if (getReferences) { | ||
405 | result.referencesOfClass.put(eClass, new TreeSet<EReference>(comparator)); | ||
406 | for (EReference eReference : eClass.getEAllReferences()) { | ||
407 | result.references.add(eReference); | ||
408 | result.referencesOfClass.get(eClass).add(eReference); | ||
409 | } | ||
410 | } | ||
411 | if (getAttrbiutes) { | ||
412 | result.attributesOfClass.put(eClass, new TreeSet<EAttribute>(comparator)); | ||
413 | for (EAttribute eAttribute : eClass.getEAllAttributes()) { | ||
414 | result.attributes.add(eAttribute); | ||
415 | result.attributesOfClass.get(eClass).add(eAttribute); | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | return result; | ||
422 | } | ||
423 | |||
424 | } | ||