/*******************************************************************************
* 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.index.util;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
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.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
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.reuseware.sokan.Filter;
import org.reuseware.sokan.SokanFactory;
import org.reuseware.sokan.Store;
import org.reuseware.sokan.index.SokanIndexPlugin;
/**
* Utility to manage stores.
*/
public final class StoreUtil {
/**
* The singleton instance.
*/
public static final StoreUtil INSTANCE = new StoreUtil();
private StoreUtil() {
deletedStores = new LinkedHashSet<Store>();
externalStores = new LinkedHashSet<URI>();
}
/**
* File extension of the .project file.
*/
public static final String FILE_EXT_PROJECT = "project";
/**
* File extension of the .store file.
*/
public static final String FILE_EXT_STORE = "store";
/**
* Name of the .project file.
*/
public static final String FILE_PROJECT = "." + FILE_EXT_PROJECT;
/**
* Name of the .store file.
*/
public static final String FILE_STORE = "." + FILE_EXT_STORE;
private Set<Store> deletedStores;
private Set<IContainer> workspaceStores;
private Set<URI> externalStores;
/**
* Obtains the filter pattern defined for the given store container.
*
* @param storeContainer the container that is a store
* @return the filter pattern
*/
public String acquireFilterPattern(IContainer storeContainer) {
if (!isStore(storeContainer) && !wasStore(storeContainer)) {
return null;
}
String filter = "";
Store store = loadStore(storeContainer);
if (store == null) {
store = loadDeletedStore(storeContainer);
}
if (store == null) {
return null;
}
for (Filter f : store.getFilters()) {
filter += f.getPattern() + ",";
}
return CoreUtil.trimLastChar(filter);
}
/**
* Obtains the filter pattern defined for the store that contains the given file.
*
* @param file the file
* @return the filter pattern
*/
public String acquireFilterPattern(IFile file) {
IContainer store = INSTANCE.getStoreContainerFor(file);
return acquireFilterPattern(store);
}
/**
* Create a store out of the given container and the given set of patterns.
*
* @param patterns the patterns
* @param container the container
* @return the store handle
*/
public Store buildStore(List<String> patterns, IContainer container) {
if (patterns == null || patterns.size() == 0) {
return null;
}
Store store = SokanFactory.eINSTANCE.createStore();
store.setUriBuffer(ResourceUtil.uriString(container));
for (String string : patterns) {
Filter filter = SokanFactory.eINSTANCE.createFilter();
filter.setPattern(string);
store.getFilters().add(filter);
}
return store;
}
/**
* Define a new store that is not inside the Eclipse workspace
* (i.e., there is no IContainer representing the store).
*
* @param storeURI the URI of the folder that is the store
*/
public void addExternalStore(URI storeURI) {
externalStores.add(storeURI);
}
/**
* Remove the store of the given container if it was marked as deleted.
*
* @param storeContainer the container that is a store
*/
public void removeDeletedStores(IContainer storeContainer) {
if (!wasStore(storeContainer)) {
return;
}
Store store = loadDeletedStore(storeContainer);
if (store != null) {
deletedStores.remove(store);
}
}
/**
* Find a resource in the resource hierarchy.
*
* @param resourceName name of the resource
* @param resources the list to which the found resource will be added
* @param parent the root of the resource hierarchy
*/
public void findResource(String resourceName, Set<IResource> resources,
IContainer parent) {
try {
if (parent instanceof IProject && !((IProject) parent).isOpen()) {
return;
}
if (parent == null || resources == null) {
return;
}
for (IResource iRes : parent.members(false)) {
if (iRes.getName().equals(resourceName)) {
resources.add(iRes);
}
if (iRes instanceof IContainer) {
findResource(resourceName, resources, (IContainer) iRes);
}
}
} catch (CoreException e) {
SokanIndexPlugin.logError("", e);
}
}
/**
* Collect the file endings of all resources in the given resource hierarchy.
*
* @param endings list in which to store the found endings
* @param parent root of the resource hierarchy
*/
public void findFileEndings(Set<String> endings, IContainer parent) {
try {
String fileEnd;
for (IResource iRes : parent.members(false)) {
if (iRes instanceof IFile) {
fileEnd = ((IFile) iRes).getFileExtension();
if (fileEnd.equals(FILE_EXT_STORE)
|| fileEnd.equals(FILE_EXT_PROJECT)) {
continue;
}
endings.add(fileEnd);
continue;
}
if (iRes instanceof IContainer) {
findFileEndings(endings, (IContainer) iRes);
}
}
} catch (CoreException e) {
SokanIndexPlugin.logError("", e);
}
}
/**
* Collect the file endings of all resources in the given resource hierarchy.
*
* @param container root of the resource hierarchy
* @return found endings
*/
public String[] grabFileEndings(IContainer container) {
Set<String> back = new TreeSet<String>();
findFileEndings(back, container);
return back.toArray(new String[0]);
}
/**
* @param container the container
* @return all stores under the given container
*/
public List<URI> getAllStoreURIs(IContainer container) {
List<URI> uris = new LinkedList<URI>();
for (IContainer con : getAllStores(container)) {
uris.add(ResourceUtil.uriFrom(con));
}
return uris;
}
/**
* Finds all stores.
*
* @return list of URIs pointing at the stores
*/
public List<URI> getAllStoreURIs() {
List<URI> uris = new LinkedList<URI>();
for (IContainer container : getWorkspaceStores()) {
uris.add(ResourceUtil.uriFrom(container));
}
uris.addAll(externalStores);
return uris;
}
/**
* @return all stores marked as deleted
*/
public List<URI> getAllDeletedStoreURIs() {
List<URI> uris = new LinkedList<URI>();
for (Store store : deletedStores) {
uris.add(ResourceUtil.uriFrom(store.getUriBuffer()));
}
return uris;
}
/**
* @param container the container
* @return all stores under the given container
*/
public Set<IContainer> getAllStores(IContainer container) {
Set<IResource> storeFiles = new LinkedHashSet<IResource>();
findResource(FILE_STORE, storeFiles, container);
if (storeFiles.size() == 0) {
return Collections.emptySet();
}
Set<IContainer> stores = new LinkedHashSet<IContainer>();
for (IResource file : storeFiles) {
stores.add(file.getParent());
}
return stores;
}
/**
* @return all stores inside the Eclipse workspace
*/
public Set<IContainer> getWorkspaceStores() {
if (workspaceStores == null) {
workspaceStores = new LinkedHashSet<IContainer>();
if (Platform.isRunning()) {
IProject[] projects = ResourcesPlugin.getWorkspace(
).getRoot().getProjects();
for (IProject project : projects) {
workspaceStores.addAll(getAllStores(project));
}
}
}
return workspaceStores;
}
/**
* @param container the container
* @return number of stores under the given container
*/
public int getStoreCount(IContainer container) {
Set<IResource> storeFiles = new LinkedHashSet<IResource>();
findResource(FILE_STORE, storeFiles, container);
return storeFiles.size();
}
/**
*
* @param resource the resource
* @return the container that is the store containing the given resource
*/
public IContainer getStoreContainerFor(IResource resource) {
if (resource == null) {
return null;
}
String resStr = resource.getFullPath().toString();
String storeStr;
for (IContainer container : getWorkspaceStores()) {
storeStr = container.getFullPath().toString();
if (resStr.equals(storeStr)) {
return container;
}
if (resStr.startsWith(storeStr + "/")) {
return container;
}
}
return null;
}
/**
* @param uri the artifacts's URI
* @return the URI of the store that contains the given artifact
*/
public URI getStoreContainerFor(URI uri) {
if (uri == null) {
return null;
}
String resStr = uri.toString();
String storeStr;
for (URI container : externalStores) {
storeStr = container.toString();
if (resStr.equals(storeStr)) {
return container;
}
if (resStr.startsWith(storeStr + "/")) {
return container;
}
}
resStr = uri.toPlatformString(true);
for (IContainer container : getWorkspaceStores()) {
storeStr = container.getFullPath().toString();
if (resStr.equals(storeStr)) {
return ResourceUtil.uriFrom(container);
}
if (resStr.startsWith(storeStr + "/")) {
return ResourceUtil.uriFrom(container);
}
}
return null;
}
/**
* @param container the container
* @return true if the container is a closed project
*/
public boolean isClosedProject(IContainer container) {
if (container == null || !container.exists() || !(container instanceof IProject)) {
return false;
}
IProject project = (IProject) container;
return !project.isOpen();
}
/**
* @param resource the resource
* @return true if the given resource is inside a store
*/
public boolean isInStore(IResource resource) {
return getStoreContainerFor(resource) != null;
}
/**
* @param uri the URI
* @return true if the artifact with the given URI is inside a store
*/
public boolean isInStore(URI uri) {
return getStoreContainerFor(uri) != null;
}
/**
* @param resource the resource
* @return true if the given resource is a container that is a store
*/
public boolean isStore(IResource resource) {
if (!(resource instanceof IContainer)) {
return false;
}
return getWorkspaceStores().contains(resource);
}
/**
* @param uri the URI
* @return true if the URI points at a store
*/
public boolean isStore(URI uri) {
if (uri.isPlatformResource() && Platform.isRunning()) {
IResource resource = ResourceUtil.fileFor(uri);
return resource.equals(getStoreContainerFor(resource));
}
return externalStores.contains(uri);
}
/**
* @param resource the resource
* @return true if the resource is a '.store' file
*/
public boolean isStoreFile(IResource resource) {
if (!(resource instanceof IFile)) {
return false;
}
return resource.getName().equals(FILE_STORE);
}
/**
* @param storeContainer a container that was unmarked as store
* @return the store handle
*/
public Store loadDeletedStore(IContainer storeContainer) {
if (storeContainer == null) {
return null;
}
String storeURIString = ResourceUtil.uriString(storeContainer);
for (Store oldStore : deletedStores) {
if (oldStore.getUriBuffer().equals(storeURIString)) {
return oldStore;
}
}
return null;
}
/**
* @param storeContainer a container that was marked as store
* @return the store handle
*/
public Store loadStore(IContainer storeContainer) {
if (!isStore(storeContainer)) {
return null;
}
// Obtain a new resource set
ResourceSet resourceSet = new ResourceSetImpl();
// IFile file = folder.getFile(StoreProjectUtil.STORE_FILE);
// String path = file.getFullPath().toString();
String path = storeContainer.getFullPath().append(FILE_STORE)
.toString();
URI uri = URI.createPlatformResourceURI(path, true);
// try open resource and retrieve
try {
Resource res = resourceSet.getResource(uri, true);
return (Store) res.getContents().get(0);
} catch (Exception e) {
return null;
}
}
/**
* @param storeContainer container
* @param store store
* @return true if successful
*/
public boolean markStore(IContainer storeContainer, Store store) {
if (storeContainer == null || store == null) {
return false;
}
if (isInStore(storeContainer) || isParentOfStore(storeContainer)
|| isClosedProject(storeContainer)) {
return false;
}
ResourceSet resourceSet = new ResourceSetImpl();
IPath path = storeContainer.getFullPath().append(FILE_STORE);
URI uri = ResourceUtil.uriFrom(path);
// create and save new resource
Resource newRes = resourceSet.createResource(uri);
try {
newRes.getContents().add(store);
newRes.save(Collections.EMPTY_MAP);
} catch (Exception e) {
SokanIndexPlugin.logError("", e);
return false;
}
getWorkspaceStores().add(storeContainer);
return true;
}
/**
* @param storeContainer the store container
* @return true if successful
*/
// TODO #1238: Reorganize Sokan API
public boolean unmarkStore(IContainer storeContainer) {
ResourceSet resourceSet = new ResourceSetImpl();
IPath path = storeContainer.getFullPath().append(FILE_STORE);
URI uri = ResourceUtil.uriFrom(path);
Resource existingRes = null;
try {
existingRes = resourceSet.getResource(uri, true);
} catch (Exception e) {
// do nothing
}
if (existingRes == null) {
return false;
}
deletedStores.add(((Store) existingRes.getContents().get(0)));
existingRes.getContents().clear();
try {
existingRes.delete(null);
} catch (IOException e) {
SokanIndexPlugin.logError("", e);
return false;
}
getWorkspaceStores().remove(storeContainer);
return true;
}
/**
* @return all deleted stores
*/
public Set<Store> getDeletedStores() {
return this.deletedStores;
}
/**
* @param storeContainer the container
* @return true if the container was unmarked as store
*/
public boolean wasStore(IContainer storeContainer) {
return loadDeletedStore(storeContainer) != null;
}
/**
* @param container the container
* @return true if the container contains itself store containers
*/
public boolean isParentOfStore(IContainer container) {
String containerString = ResourceUtil.uriString(container) + "/";
for (URI storeURI : getAllStoreURIs()) {
if (ResourceUtil.uriString(storeURI).startsWith(containerString)) {
return true;
}
}
return false;
}
}