blob: 1423fb977d2c10bb24e6d0c510f32a3bdf955574 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2015 Obeo and others.
* 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:
* Obeo - initial API and implementation
* Stefan Dirix - bug 460780
*******************************************************************************/
package org.eclipse.emf.compare.uml2.ide;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.ide.hook.IResourceSetHook;
import org.eclipse.emf.compare.uml2.rcp.internal.policy.UMLLoadOnDemandPolicy;
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 org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl;
import org.eclipse.uml2.common.util.CacheAdapter;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
/**
* The {@link UMLLoadOnDemandPolicy} will load profiles in the resource set used by EMF Compare. These will be
* referenced in package registries and extended meta-data for their resource set. We want them to be properly
* unloaded and will do so from here.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public class ResourceSetProfileUnloader extends UMLLoadOnDemandPolicy implements IResourceSetHook {
/**
* Returns true if this hook should be used.
*
* @param uris
* list of {@link URI}s about to be loaded in the {@link ResourceSet}.
* @return <code>true</code> if this hook should be used, <code>false</code> otherwise.
*/
public boolean isHookFor(Collection<? extends URI> uris) {
for (URI uri : uris) {
if (UML_EXTENSION.equals(uri.fileExtension())) {
return true;
}
}
return false;
}
/**
* This will be called before the final resource set is populated, in unspecified order. Resource set
* hooks can load resource in this resource set and thus an individual hook is not guaranteed to be
* provided an empty resource set here.
*
* @param resourceSet
* about to be filled.
* @param uris
* {@link URI}s that the resource set has been requested to load. The {@link Collection} of
* {@link URI} is not modifiable.
*/
public void preLoadingHook(ResourceSet resourceSet, Collection<? extends URI> uris) {
// We're not interested in this event
}
/**
* This will be called after the resource set is populated in an unspecified order.
*
* @param resourceSet
* that has been filled with {@link org.eclipse.emf.ecore.resource.Resource}s.
* @param uris
* {@link URI}s that the resource set has been requested to load.The {@link Collection} of
* {@link URI} is not modifiable.
*/
public void postLoadingHook(ResourceSet resourceSet, Collection<? extends URI> uris) {
// We're not interested in this event
}
/**
* This will be called when the resource set is disposed (if it is).
* <p>
* By default, EMF Compare will not unload any resource. Still some resources might need to be unloaded.
* This method could be a good way to do it. Hooks are called in unspecified order, so resources may
* already have been unloaded by other hooks when yours is called.
* </p>
*
* @param resources
* List of {@link Resource}s currently in the resource set.
*/
public void onDispose(Iterable<Resource> resources) {
URIConverter uriConverter = new ExtensibleURIConverterImpl();
for (Resource resource : resources) {
if (resource.isLoaded()) {
URI uri = resource.getURI();
URI normalizedURI = uriConverter.normalize(uri);
if (isConventionalURIForUMLProfile(normalizedURI) || isUMLMetaModel(normalizedURI)
|| isRegisteredUMLProfile(normalizedURI, uriConverter)) {
for (EObject child : resource.getContents()) {
// TODO Are profiles always at the root?
if (child instanceof Profile) {
disposeProfileApplications((Profile)child);
break;
}
}
resource.unload();
}
}
}
}
/**
* UML will hold onto the profiles in memory even if we unload them completely unless we do the same for
* the resources they're referenced from.
*
* @param profile
* The profile which applications we need to dispose of.
*/
private void disposeProfileApplications(Profile profile) {
final Set<Resource> unloadMe = new LinkedHashSet<Resource>();
Collection<EStructuralFeature.Setting> settings = CacheAdapter.getInstance()
.getInverseReferences(profile, false);
for (EStructuralFeature.Setting setting : settings) {
if (setting.getEObject() instanceof ProfileApplication) {
unloadMe.add(setting.getEObject().eResource());
}
}
for (Resource unload : unloadMe) {
if (unload.isLoaded()) {
unload.unload();
}
}
}
}