/*******************************************************************************
* Copyright (c) 2005, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
/*
* $$RCSfile: WorkbenchURIConverterImpl.java,v $$
* $$Revision: 1.6 $$ $$Date: 2006/05/17 20:13:45 $$
*/
package net.enilink.komma.workbench;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.enilink.komma.core.URI;
import net.enilink.komma.core.URIs;
import net.enilink.komma.model.ModelUtil;
import net.enilink.komma.model.base.ExtensibleURIConverter;
import net.enilink.komma.model.base.IURIMapRule;
import net.enilink.komma.model.base.SimpleURIMapRule;
import net.enilink.komma.workbench.internal.KommaWorkbenchPlugin;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
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.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
/**
* A default implementation of the WorkbenchURIConverter interface.
*
* @since 1.0.0
*/
public class WorkbenchURIConverterImpl extends ExtensibleURIConverter implements
IWorkbenchURIConverter, IResourceChangeListener, AutoCloseable {
protected List<IContainer> inputContainers = new ArrayList<>();
protected Map<IPath, IURIMapRule> ruleMap = new HashMap<>();
protected Set<String> supportedExtensions = new HashSet<>(Arrays.asList(
"owl", "rdf", "n3", "ttl", "nt"));
protected Map<IProject, List<IProject>> projectDependencies = new HashMap<>();
protected Map<IProject, Integer> trackedProjects = new HashMap<>();
/**
* Default converter constructor, no containers.
*/
public WorkbenchURIConverterImpl() {
}
/**
* Construct with an input container.
*
* @param inputContainer
*/
public WorkbenchURIConverterImpl(IContainer inputContainer) {
addInputContainer(inputContainer);
}
protected void addRules(Collection<? extends IContainer> containers) {
try {
for (IContainer container : containers) {
container.accept(new IResourceVisitor() {
@Override
public boolean visit(IResource resource)
throws CoreException {
if (resource.getType() == IResource.FILE) {
addRule((IFile) resource);
}
return true;
}
});
}
} catch (CoreException e) {
KommaWorkbenchPlugin.INSTANCE.log(e);
}
}
protected void updateDependencies(IProject project,
List<IProject> dependencies) throws CoreException {
List<IProject> last = projectDependencies.get(project);
if (last == null) {
last = Collections.emptyList();
}
Set<IProject> toRemove = new HashSet<>(last);
toRemove.removeAll(dependencies);
Set<IProject> toAdd = new HashSet<>(dependencies);
toAdd.removeAll(last);
for (Iterator<IProject> it = toAdd.iterator(); it.hasNext();) {
IProject p = it.next();
Integer refCount = trackedProjects.get(p);
if (refCount != null) {
it.remove();
}
trackedProjects.put(p, refCount != null ? refCount + 1 : 1);
}
for (Iterator<IProject> it = toRemove.iterator(); it.hasNext();) {
IProject p = it.next();
Integer refCount = trackedProjects.get(p);
if (refCount == null || refCount <= 1) {
trackedProjects.remove(p);
} else {
trackedProjects.put(p, refCount - 1);
it.remove();
}
}
addRules(toAdd);
removeRules(toRemove);
if (dependencies.isEmpty()) {
projectDependencies.remove(project);
} else {
projectDependencies.put(project, dependencies);
}
}
public void addInputContainer(IContainer container) {
if (container != null && !getInputContainers().contains(container)) {
inputContainers.add(container);
ResourcesPlugin.getWorkspace().addResourceChangeListener(this,
IResourceChangeEvent.POST_CHANGE);
addRules(Collections.singleton(container));
if (container.getType() == IResource.PROJECT
&& container.isAccessible()) {
try {
updateDependencies((IProject) container,
Arrays.asList(((IProject) container)
.getReferencedProjects()));
} catch (CoreException e) {
KommaWorkbenchPlugin.INSTANCE.log(e);
}
}
}
}
protected void addRule(IFile file) {
if (!supportedExtensions.contains(file.getFileExtension())
|| ruleMap.containsKey(file.getFullPath())) {
return;
}
URI fileURI = URIs.createPlatformResourceURI(file.getFullPath()
.toString(), true);
String ontology = null;
try {
ontology = ModelUtil.findOntology(file.getContents(), fileURI
.toString(), ModelUtil.mimeType(ModelUtil
.contentDescription(this, fileURI)));
} catch (Exception e) {
// ignore parse exception
}
if (ontology == null) {
ontology = fileURI.toString();
}
SimpleURIMapRule rule = new SimpleURIMapRule(file.isDerived() ? 10 : 0,
ontology, fileURI.toString());
ruleMap.put(file.getFullPath(), rule);
getURIMapRules().addRule(rule);
}
public List<IContainer> getInputContainers() {
return inputContainers;
}
protected void removeRules(Collection<? extends IContainer> containers) {
try {
for (IContainer container : containers) {
if (container.isAccessible()) {
container.accept(new IResourceVisitor() {
@Override
public boolean visit(IResource resource)
throws CoreException {
if (resource.getType() == IResource.FILE) {
removeRule((IFile) resource);
}
return true;
}
});
}
}
} catch (CoreException e) {
KommaWorkbenchPlugin.INSTANCE.log(e);
}
}
public boolean removeInputContainer(IContainer container) {
if (inputContainers.remove(container)) {
removeRules(Collections.singleton(container));
if (container.getType() == IResource.PROJECT) {
try {
updateDependencies((IProject) container,
Collections.<IProject> emptyList());
} catch (CoreException e) {
KommaWorkbenchPlugin.INSTANCE.log(e);
}
}
if (inputContainers.isEmpty()) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(
this);
}
return true;
}
return false;
}
protected void removeRule(IFile file) {
IURIMapRule rule = ruleMap.remove(file.getFullPath());
if (rule != null) {
getURIMapRules().removeRule(rule);
}
}
@Override
public void resourceChanged(IResourceChangeEvent event) {
IResourceDelta delta = event.getDelta();
try {
delta.accept(new IResourceDeltaVisitor() {
@Override
public boolean visit(IResourceDelta delta) throws CoreException {
int type = delta.getResource().getType();
if ((type == IResource.PROJECT || type == IResource.FOLDER)
&& delta.getMovedToPath() != null
&& inputContainers.contains(delta.getResource())) {
IResource newContainer = ResourcesPlugin.getWorkspace()
.getRoot().findMember(delta.getMovedToPath());
removeInputContainer((IContainer) delta.getResource());
// remove rules for contained files
delta.accept(new IResourceDeltaVisitor() {
@Override
public boolean visit(IResourceDelta delta)
throws CoreException {
if (delta.getResource().getType() == IResource.FILE) {
removeRule((IFile) delta.getResource());
}
return true;
}
});
addInputContainer((IContainer) newContainer);
return false;
} else if (type == IResource.PROJECT
&& inputContainers.contains(delta.getResource())
&& delta.getResource().isAccessible()) {
IProject p = (IProject) delta.getResource();
updateDependencies(p,
Arrays.asList(p.getReferencedProjects()));
} else if (type == IResource.FILE
&& supportedExtensions.contains(delta.getResource()
.getFileExtension())) {
boolean isRelevant = false;
for (IContainer container : inputContainers) {
isRelevant = container.getFullPath().isPrefixOf(
delta.getFullPath());
if (isRelevant) {
break;
}
}
isRelevant |= trackedProjects.containsKey(delta
.getResource().getProject());
if (isRelevant) {
if (delta.getKind() == IResourceDelta.ADDED) {
addRule((IFile) delta.getResource());
} else if (delta.getKind() == IResourceDelta.REMOVED) {
removeRule((IFile) delta.getResource());
} else if (delta.getKind() == IResourceDelta.CHANGED
&& delta.getFlags() != IResourceDelta.MARKERS) {
removeRule((IFile) delta.getResource());
addRule((IFile) delta.getResource());
}
}
}
return true;
}
});
} catch (CoreException e) {
KommaWorkbenchPlugin.INSTANCE.log(e);
}
}
@Override
public void close() throws Exception {
IWorkspace ws = ResourcesPlugin.getWorkspace();
if (ws != null) {
ws.removeResourceChangeListener(this);
}
trackedProjects.clear();
}
}