/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* 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:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.reuseware.sokan.resource.build;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.util.URI;
import org.reuseware.sokan.index.SokanIndexPlugin;
import org.reuseware.sokan.index.util.IndexUtil;
import org.reuseware.sokan.index.util.ResourceUtil;
import org.reuseware.sokan.index.util.StoreUtil;
import org.reuseware.sokan.resource.ui.StoreDecorator;
import org.reuseware.sokan.resource.util.BuildUtil;
import org.reuseware.sokan.resource.util.FilterUtil;
/**
* A resource visitor used by the <code>IndexBuilder</code> to
* visit and index artifacts that have changed in the workspace.
*/
public class StoreDeltaVisitor implements IResourceDeltaVisitor {
private final StoreUtil storeUtil = StoreUtil.INSTANCE;
private List<URI> storeURIs;
private boolean isFirstVisit;
/**
* Constructs a new StoreDeltaVisitor.
*/
public StoreDeltaVisitor() {
storeURIs = storeUtil.getAllStoreURIs();
isFirstVisit = true;
}
/**
* Visits the given resource delta to update the index for
* all artifacts in the delta.
*
* @param delta the resource delta
*
* @return true if a folder inside a store is visited (to visit its children)
*
* @throws CoreException if the visit fails for some reason.
*/
public boolean visit(IResourceDelta delta) throws CoreException {
if (isFirstVisit) {
isFirstVisit = false;
// CoreUtil.print(delta, 0);
// we need deleted stores for later calculations in StoreUtil
handleStoreMarkerFiles(delta);
}
// is delta's resource relevant?
IResource res = delta.getResource();
URI resURI = ResourceUtil.uriFrom(res);
boolean isRelevant = false;
String resStr = resURI.toString();
String storeStr;
for (URI storeURI : storeURIs) {
storeStr = storeURI.toString();
if (storeStr.startsWith(resStr) || resStr.startsWith(storeStr)) {
isRelevant = true;
break;
}
}
if (!isRelevant) {
return false;
}
// if complete store changed: handle separately
if (isRelevantStoreContainer(res)) {
for (IResourceDelta childDelta : delta.getAffectedChildren()) {
if (storeUtil.isStoreFile(childDelta.getResource())) {
handleCompleteStore(delta);
return false;
}
}
}
// if no file, go on
if (!(res instanceof IFile)) {
return true;
}
// check file is INSIDE a store
IFile file = (IFile) res;
if (!isInRelevantStore(resStr)) {
return false;
}
// check file meets filterPattern
String filterPattern = storeUtil.acquireFilterPattern(file);
if (!FilterUtil.isArtifact(file, filterPattern)) {
return false;
}
// we found an artifact to handle in index
handleArtifact(delta);
return false;
}
private boolean isInRelevantStore(String resStr) {
boolean isRelevant = false;
String storeStr;
for (URI storeURI : storeURIs) {
storeStr = storeURI.toString();
if (resStr.startsWith(storeStr)) {
isRelevant = true;
break;
}
}
return isRelevant;
}
private boolean isRelevantStoreContainer(IResource res) {
if (!(res instanceof IContainer)) {
return false;
}
URI uri = ResourceUtil.uriFrom(res);
return storeURIs.contains(uri);
}
private void handleStoreMarkerFiles(IResourceDelta delta) {
IResource res = delta.getResource();
if (storeUtil.isStoreFile(res)) {
if (delta.getKind() == IResourceDelta.REMOVED) {
if (res.getParent() instanceof IContainer) {
IContainer store = (IContainer) res.getParent();
if (!storeUtil.wasStore(store)) {
//file has been manually deleted, we have to reconstruct a store object
storeUtil.getDeletedStores().add(StoreUtil.INSTANCE.buildStore(
Collections.singletonList("*.*"), store));
storeUtil.getWorkspaceStores().remove(store);
StoreDecorator.refresh(store);
}
storeURIs.add(ResourceUtil.uriFrom(store));
}
return;
}
if (delta.getKind() == IResourceDelta.ADDED) {
if (res.getParent() instanceof IContainer) {
IContainer store = (IContainer) res.getParent();
storeUtil.getWorkspaceStores().add(store);
storeURIs.add(ResourceUtil.uriFrom(store));
StoreDecorator.refresh(store);
}
return;
}
}
IResourceDelta[] children = delta.getAffectedChildren();
for (IResourceDelta childDelta : children) {
handleStoreMarkerFiles(childDelta);
}
}
private void handleArtifact(IResourceDelta delta) {
if (!(delta.getResource() instanceof IFile)) {
return;
}
IFile artifact = (IFile) delta.getResource();
// Do not index hidden files
if (artifact.getName().startsWith(".")) {
return;
}
switch (delta.getKind()) {
case IResourceDelta.ADDED:
IndexUtil.INSTANCE.addArtifact(artifact);
break;
case IResourceDelta.REMOVED:
IndexUtil.INSTANCE.removeArtifact(artifact);
break;
case IResourceDelta.CHANGED:
if (IndexUtil.INSTANCE.isArtifact(artifact)) {
IndexUtil.INSTANCE.updateArtifact(artifact);
} else {
IndexUtil.INSTANCE.addArtifact(artifact);
}
break;
default:
SokanIndexPlugin.logError(
"Unknown delta kind while handling artifact ("
+ "File: " + artifact + ", "
+ "Kind: " + delta.getKind() + ")", null);
break;
}
}
private void handleCompleteStore(IResourceDelta delta) {
if (!(delta.getResource() instanceof IContainer)) {
return;
}
IContainer store = (IContainer) delta.getResource();
IResourceDelta delStoreFile = null;
for (IResourceDelta childDelta : delta.getAffectedChildren()) {
if (storeUtil.isStoreFile(childDelta.getResource())) {
delStoreFile = childDelta;
break;
}
}
if (delStoreFile == null) {
return;
}
switch (delStoreFile.getKind()) {
case IResourceDelta.ADDED:
handleCompleteStore(store, true);
break;
case IResourceDelta.REMOVED:
handleCompleteStore(store, false);
break;
case IResourceDelta.CHANGED:
updateCompleteStore(store);
break;
default:
SokanIndexPlugin.logError(
"Unknown delta kind while handling complete store ("
+ "Store: " + store + ", "
+ "Kind: " + delStoreFile.getKind() + ")", null);
break;
}
}
private void handleCompleteStore(IContainer store, boolean addMode) {
String pattern = storeUtil.acquireFilterPattern(store);
BuildUtil.visitStore(store, pattern, addMode);
}
//TODO #1470: check if this can be implemented more efficiently than just re-adding the store
private void updateCompleteStore(IContainer store) {
// needed when content of .store files changes => filterPattern
// hence, adds and removes single artifacts
// think about following scenario:
// .store gets updated, relevant artifact gets deleted
handleCompleteStore(store, false);
handleCompleteStore(store, true);
}
}