blob: 5c3abae6e6bba4bd55e5ac9922452add9875fc9f [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2000,2002 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
**********************************************************************/
package org.eclipse.core.internal.properties;
import java.util.Enumeration;
import java.util.List;
import org.eclipse.core.internal.events.ILifecycleListener;
import org.eclipse.core.internal.events.LifecycleEvent;
import org.eclipse.core.internal.resources.*;
import org.eclipse.core.internal.utils.Assert;
import org.eclipse.core.internal.utils.Policy;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
/**
*
*/
public class PropertyManager implements IManager, ILifecycleListener {
protected Workspace workspace;
public PropertyManager(Workspace workspace) {
this.workspace = workspace;
}
public void closePropertyStore(IResource target) throws CoreException {
Resource host = (Resource) getPropertyHost(target);
ResourceInfo info = (ResourceInfo) host.getResourceInfo(false, false);
if (info == null)
return;
PropertyStore store = info.getPropertyStore();
if (store == null)
return;
synchronized (store) {
store.shutdown(null);
setPropertyStore(target, null);
}
}
/**
* Copy all the properties of one resource to another. Both resources
* must have a property store available.
*/
public void copy(IResource source, IResource destination, int depth) throws CoreException {
// cache stores to avoid problems in concurrency
PropertyStore sourceStore = getPropertyStore(source);
PropertyStore destinationStore = getPropertyStore(destination);
synchronized (sourceStore) {
synchronized (destinationStore) {
copyProperties(source, destination, depth);
sourceStore.commit();
destinationStore.commit();
}
}
}
protected void copyProperties(IResource source, IResource destination, int depth) throws CoreException {
PropertyStore sourceStore = getPropertyStore(source);
PropertyStore destStore = getPropertyStore(destination);
ResourceName sourceName = getPropertyKey(source);
ResourceName destName = getPropertyKey(destination);
QueryResults results = sourceStore.getAll(sourceName, depth);
for (Enumeration resources = results.getResourceNames(); resources.hasMoreElements();) {
ResourceName resourceName = (ResourceName) resources.nextElement();
List properties = results.getResults(resourceName);
if (properties.isEmpty())
continue;
StoredProperty[] propsArray = new StoredProperty[properties.size()];
propsArray = (StoredProperty[]) properties.toArray(propsArray);
int segmentsToDrop = source.getProjectRelativePath().matchingFirstSegments(resourceName.getPath());
IPath path = destName.getPath().append(resourceName.getPath().removeFirstSegments(segmentsToDrop));
resourceName = new ResourceName(resourceName.getQualifier(), path);
destStore.set(resourceName, propsArray, IResource.DEPTH_ZERO, PropertyStore.SET_UPDATE);
}
}
public void deleteProperties(IResource target) throws CoreException {
deleteProperties(target, IResource.DEPTH_INFINITE);
}
public void deleteProperties(IResource target, int depth) throws CoreException {
switch (target.getType()) {
case IResource.FILE :
case IResource.FOLDER :
PropertyStore store = getPropertyStore(target);
synchronized (store) {
store.removeAll(getPropertyKey(target), depth);
store.commit();
}
break;
case IResource.PROJECT :
case IResource.ROOT :
deletePropertyStore(target);
}
}
protected void deletePropertyStore(IResource target) throws CoreException {
closePropertyStore(target);
workspace.getMetaArea().getPropertyStoreLocation(target).toFile().delete();
}
/**
* Returns the value of the identified property on the given resource as
* maintained by this store.
*/
public String getProperty(IResource target, QualifiedName name) throws CoreException {
PropertyStore store = getPropertyStore(target);
synchronized (store) {
StoredProperty result = store.get(getPropertyKey(target), name);
return result == null ? null : result.getStringValue();
}
}
/**
* Returns the resource which hosts the property store
* for the given resource.
*/
protected IResource getPropertyHost(IResource target) {
return target.getType() == IResource.ROOT ? target : target.getProject();
}
/**
* Returns the key to use in the property store when accessing
* the properties of the given resource.
*/
protected ResourceName getPropertyKey(IResource target) {
return new ResourceName("", target.getProjectRelativePath()); //$NON-NLS-1$
}
/**
* Returns the property store to use when storing a property for the
* given resource.
* @throws CoreException if the store could not be obtained for any reason.
*/
protected PropertyStore getPropertyStore(IResource target) throws CoreException {
try {
Resource host = (Resource) getPropertyHost(target);
ResourceInfo info = (ResourceInfo) host.getResourceInfo(false, false);
if (info == null) {
String message = Policy.bind("properties.storeNotAvailable", target.getFullPath().toString()); //$NON-NLS-1$
throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, target.getFullPath(), message, null);
}
PropertyStore store = info.getPropertyStore();
if (store == null)
store = openPropertyStore(host);
return store;
} catch (Exception e) {
if (e instanceof CoreException)
throw (CoreException)e;
String message = Policy.bind("properties.storeNotAvailable", target.getFullPath().toString()); //$NON-NLS-1$
throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, target.getFullPath(), message, e);
}
}
public void handleEvent(LifecycleEvent event) throws CoreException {
if (event.kind == LifecycleEvent.PRE_PROJECT_CLOSE)
closePropertyStore(event.resource);
}
protected PropertyStore openPropertyStore(IResource target) {
int type = target.getType();
Assert.isTrue(type != IResource.FILE && type != IResource.FOLDER);
IPath location = workspace.getMetaArea().getPropertyStoreLocation(target);
java.io.File storeFile = location.toFile();
new java.io.File(storeFile.getParent()).mkdirs();
PropertyStore store = new PropertyStore(location);
setPropertyStore(target, store);
return store;
}
public void setProperty(IResource target, QualifiedName key, String value) throws CoreException {
PropertyStore store = getPropertyStore(target);
synchronized (store) {
if (value == null) {
store.remove(getPropertyKey(target), key);
} else {
StoredProperty prop = new StoredProperty(key, value);
store.set(getPropertyKey(target), prop);
}
store.commit();
}
}
protected void setPropertyStore(IResource target, PropertyStore value) {
// fetch the info but don't bother making it mutable even though we are going
// to modify it. We don't know whether or not the tree is open and it really doesn't
// matter as the change we are doing does not show up in deltas.
ResourceInfo info = ((Resource) getPropertyHost(target)).getResourceInfo(false, false);
if (info.getType() == IResource.PROJECT)
((ProjectInfo) info).setPropertyStore(value);
else
((RootInfo) info).setPropertyStore(value);
}
public void shutdown(IProgressMonitor monitor) throws CoreException {
closePropertyStore(workspace.getRoot());
}
public void startup(IProgressMonitor monitor) throws CoreException {
workspace.addLifecycleListener(this);
}
}