blob: d7bb957fc8c3b0ee4c8052e33567c26b14c1ec6c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Obeo.
* 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 and/or initial documentation
* ...
*******************************************************************************/
package org.eclipse.intent.mapping.emf.ide;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
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.XMIResourceFactoryImpl;
import org.eclipse.intent.mapping.Base;
import org.eclipse.intent.mapping.MappingPackage;
import org.eclipse.intent.mapping.MappingUtils;
/**
* An {@link IResourceChangeListener} that
* {@link org.eclipse.intent.mapping.base.IBaseRegistry#register(org.eclipse.intent.mapping.base.IBase)
* register}/
* {@link org.eclipse.intent.mapping.base.IBaseRegistry#unregister(org.eclipse.intent.mapping.base.IBase)
* unregister} {@link Base} of the {@link org.eclipse.intent.mapping.base.IBaseRegistry}.
*
* @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
*/
public class WorkspaceMappingBaseListener implements IResourceChangeListener {
/**
* The "Unable to load mapping base from " message.
*/
private static final String UNABLE_TO_LOAD_MAPPING_BASE_FROM = "Unable to load mapping base from ";
/**
* Mapping of {@link IFile} to
* {@link org.eclipse.intent.mapping.base.IBaseRegistry#register(org.eclipse.intent.mapping.base.IBase)
* registered} {@link Base}.
*/
private final Map<IFile, Base> resourceToBase = new HashMap<IFile, Base>();
/**
* Constructor.
*
* @param scan
* tells if we should scan the workspace
*/
public WorkspaceMappingBaseListener(boolean scan) {
if (scan) {
scan(ResourcesPlugin.getWorkspace().getRoot());
}
}
/**
* Scans the given {@link IContainer} for bases.
*
* @param container
* the {@link IContainer}
*/
private void scan(IContainer container) {
IResource[] members;
if (container.isAccessible()) {
try {
members = container.members();
for (IResource member : members) {
if (member instanceof IContainer) {
scan((IContainer)member);
} else if (member instanceof IFile) {
register((IFile)member);
}
}
} catch (CoreException e) {
Activator.getDefault().getLog().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID,
UNABLE_TO_LOAD_MAPPING_BASE_FROM + e.getMessage(), e));
}
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
*/
public void resourceChanged(IResourceChangeEvent event) {
if (event.getDelta() != null) {
walkDelta(event.getDelta(), new HashMap<IPath, IResource>());
}
}
/**
* Walks the {@link IResourceDelta} tree.
*
* @param delta
* the root {@link IResourceDelta}
* @param movedResources
* mapping of moved {@link IResource}
*/
private void walkDelta(IResourceDelta delta, HashMap<IPath, IResource> movedResources) {
processDelta(delta, movedResources);
for (IResourceDelta child : delta.getAffectedChildren()) {
walkDelta(child, movedResources);
}
}
/**
* Processes the given {@link IResourceDelta} by
* {@link WorkspaceListener#fireChange(fr.obeo.dsl.workspace.listener.change.IChange) firing}
* {@link fr.obeo.dsl.workspace.listener.change.IChange IChange}.
*
* @param delta
* the {@link IResourceDelta} to process
* @param movedResources
* mapping of moved {@link IResource}
*/
private void processDelta(IResourceDelta delta, HashMap<IPath, IResource> movedResources) {
if (delta.getResource() instanceof IFile) {
switch (delta.getKind()) {
case IResourceDelta.ADDED:
processAddedDelta(delta, movedResources);
break;
case IResourceDelta.REMOVED:
processRemovedDelta(delta, movedResources);
break;
case IResourceDelta.CHANGED:
processChangedDelta(delta);
break;
default:
break;
}
}
}
/**
* Process {@link IResourceDelta} with {@link IResourceDelta#CHANGED changed}
* {@link IResourceDelta#getKind() kind}.
*
* @param delta
* the {@link IResourceDelta} with {@link IResourceDelta#CHANGED changed}
* {@link IResourceDelta#getKind() kind}
*/
private void processChangedDelta(IResourceDelta delta) {
if ((delta.getFlags() & IResourceDelta.OPEN) != 0) {
if (delta.getResource().isAccessible()) {
register((IFile)delta.getResource());
} else {
unregister((IFile)delta.getResource());
}
} else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
// nothing to do here
} else if ((delta.getFlags() & IResourceDelta.CONTENT) != 0) {
if (resourceToBase.get(delta.getResource()) == null) {
register((IFile)delta.getResource());
}
}
}
/**
* Process {@link IResourceDelta} with {@link IResourceDelta#REMOVED removed}
* {@link IResourceDelta#getKind() kind}.
*
* @param delta
* the {@link IResourceDelta} with {@link IResourceDelta#REMOVED removed}
* {@link IResourceDelta#getKind() kind}
* @param movedResources
* mapping of moved {@link IResource}
*/
private void processRemovedDelta(IResourceDelta delta, HashMap<IPath, IResource> movedResources) {
if ((delta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
final IResource target = movedResources.get(delta.getMovedToPath());
if (target != null) {
resourceMoved((IFile)delta.getResource(), (IFile)target);
} else {
movedResources.put(delta.getResource().getFullPath(), delta.getResource());
}
} else {
unregister((IFile)delta.getResource());
}
}
/**
* Process {@link IResourceDelta} with {@link IResourceDelta#ADDED added} {@link IResourceDelta#getKind()
* kind}.
*
* @param delta
* the {@link IResourceDelta} with {@link IResourceDelta#ADDED added}
* {@link IResourceDelta#getKind() kind}
* @param movedResources
* mapping of moved {@link IResource}
*/
private void processAddedDelta(IResourceDelta delta, HashMap<IPath, IResource> movedResources) {
if ((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0) {
final IResource source = movedResources.get(delta.getMovedFromPath());
if (source != null) {
resourceMoved((IFile)source, (IFile)delta.getResource());
} else {
movedResources.put(delta.getResource().getFullPath(), delta.getResource());
}
} else {
register((IFile)delta.getResource());
}
}
/**
* Handles a {@link IFile} move.
*
* @param source
* the source {@link IFile}
* @param target
* the target {@link IFile}
*/
private void resourceMoved(IFile source, IFile target) {
if (MappingPackage.eNAME.equals(source.getFileExtension())) {
if (MappingPackage.eNAME.equals(target.getFileExtension())) {
final Base base = resourceToBase.remove(source);
resourceToBase.put(target, base);
} else {
unregister(source);
}
} else {
if (MappingPackage.eNAME.equals(target.getFileExtension())) {
register(target);
} else {
// nothing to do here
}
}
}
/**
* {@link org.eclipse.intent.mapping.base.IBaseRegistry#register(org.eclipse.intent.mapping.base.IBase)
* Unregisters} the {@link Base} stored in the given {@link IFile} if any, does nothing otherwise.
*
* @param file
* the {@link IFile}
*/
private void register(IFile file) {
final Base base = getBaseFromFile(file);
if (base != null) {
resourceToBase.put(file, base);
MappingUtils.getMappingRegistry().register(base);
}
}
/**
* Gets the {@link Base} from the given {@link IFile}.
*
* @param file
* the {@link IFile}
* @return the {@link Base} from the given {@link IFile} if nay, <code>null</code> otherwise
*/
private Base getBaseFromFile(IFile file) {
Base res = null;
if (MappingPackage.eNAME.equals(file.getFileExtension())) {
try {
final ResourceSet resourceSet = new ResourceSetImpl();
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(MappingPackage.eNAME,
new XMIResourceFactoryImpl());
final Resource resource = resourceSet.getResource(URI.createPlatformResourceURI(file
.getFullPath().toString(), true), true);
if (!resource.getContents().isEmpty()) {
if (resource.getContents().get(0) instanceof Base) {
res = (Base)resource.getContents().get(0);
} else {
Activator.getDefault().getLog().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID,
UNABLE_TO_LOAD_MAPPING_BASE_FROM + file.getFullPath().toString()
+ " doesn't contain a Base."));
}
} else {
Activator.getDefault().getLog().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID,
UNABLE_TO_LOAD_MAPPING_BASE_FROM + file.getFullPath().toString()
+ " resource is empty"));
}
// CHECKSTYLE:OFF
} catch (Exception e) {
// CHECKSTYLE:ON
Activator.getDefault().getLog().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID,
UNABLE_TO_LOAD_MAPPING_BASE_FROM + file.getFullPath().toString(), e));
}
}
return res;
}
/**
* {@link org.eclipse.intent.mapping.base.IBaseRegistry#unregister(org.eclipse.intent.mapping.base.IBase)
* Unregisters} the {@link Base} corresponding to the given {@link IFile}.
*
* @param file
* the {@link IFile}
*/
private void unregister(IFile file) {
final Base base = resourceToBase.remove(file);
if (base != null) {
MappingUtils.getMappingRegistry().unregister(base);
}
}
}