blob: 47710ab04db681685c6703f111a50c5fd5b446c3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2006 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
*******************************************************************************/
package org.eclipse.wst.common.componentcore.internal.resources;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/**
* Maps resources to cached data and remembers when the data was cached based on a timestamp
* signature of a given resource.
*
*/
public class ResourceTimestampMappings {
private static final IPath COMPONENT_MANIFEST_PATH = new Path(".settings/org.eclipse.wst.common.component");
private static final IPath FACET_CONFIG_PATH = new Path(".settings/org.eclipse.wst.common.project.facet.core.xml");
private static final Object NO_DATA = new Object();
private static final Object ERROR = new Object();
private final Map timestamps = new HashMap();
private final Map data = new HashMap();
/**
* Record a timestamp signature for the given resource.
* <p>
* Clients may use {@link #hasChanged(IResource)} to determine if the resource has changed since
* it was recorded.
* </p>
*
* @param resource
* The resource that was processed.
* @return True if the recording was successfull. The recording may fail if the resource does
* not exist.
*
* @see #hasChanged(IResource)
*/
public synchronized boolean mark(IResource resource) {
return mark(resource, NO_DATA);
}
/**
* Cache the data that was determined when processing the resource. The a timestamp signature
* will be recorded for the resource as well.
*
* <p>
* Clients may use {@link #hasChanged(IResource)} to determine if the cached data should be
* replaced.
* </p>
*
* @param resource
* The resource that was processed.
* @param cachedData
* The data that was determined when the Resource was processed.
*
* @return True if the recording was successfull. The recording may fail if the resource does
* not exist.
*
*
* @see #hasChanged(IResource)
* @see #hasCacheData(IResource)
*/
public synchronized boolean mark(IResource resource, Object cachedData) {
if (resource.getModificationStamp() != IResource.NULL_STAMP) {
if (timestamps.containsKey(resource)) {
TimestampSignature signature = (TimestampSignature) timestamps.get(resource);
signature.update(resource);
} else {
timestamps.put(resource, createTimestampSignature(resource));
}
data.put(resource, cachedData);
return true;
}
return false;
}
/**
* Note that an error occurred when processing this resource.
*
* @param resource
* The resource that had some sort of error while processing.
* @return True if the error was recorded. The error may not be recorded if the resource does
* not exist.
* @see #hasCacheError(IResource)
*/
public synchronized boolean markError(IResource resource) {
if (resource.getModificationStamp() != IResource.NULL_STAMP) {
if (timestamps.containsKey(resource)) {
TimestampSignature signature = (TimestampSignature) timestamps.get(resource);
signature.update(resource);
} else {
timestamps.put(resource, createTimestampSignature(resource));
}
data.put(resource, ERROR);
return true;
}
return false;
}
/**
*
* @param resource
* The resource that was or is about to be processed.
* @return True if the given resource has changed in a noticeable way since it was marked.
*
* @see #mark(IResource)
* @see #mark(IResource, Object)
* @see #markError(IResource)
*/
public boolean hasChanged(IResource resource) {
TimestampSignature signature = (TimestampSignature) timestamps.get(resource);
return signature == null || signature.hasChanged(resource);
}
/**
*
* @param resource
* The resource that was or is about to be processed.
* @return True if there is any data cached for the given resource.
*
* @see #mark(IResource)
* @see #mark(IResource, Object)
* @see #markError(IResource)
*/
public boolean hasCacheData(IResource resource) {
Object datum = data.get(resource);
return datum != null && datum != NO_DATA;
}
/**
*
* @param resource
* The resource that was or is about to be processed.
* @return True if there is any data cached for the given resource.
*
* @see #mark(IResource)
* @see #mark(IResource, Object)
* @see #markError(IResource)
*/
public boolean hasCacheError(IResource resource) {
return data.get(resource) == ERROR;
}
public Object getData(IResource resource) {
Object datum = data.get(resource);
if (datum != NO_DATA)
return datum;
return null;
}
private TimestampSignature createTimestampSignature(IResource resource) {
switch (resource.getType()) {
case IResource.PROJECT :
return new ProjectTimestamp((IProject) resource);
default :
return new SimpleResourceTimestamp(resource);
}
}
/**
* Provides a point in time signature of a Resource to determine whether that resource has
* changed in a meaningful way since the time this signature was created or last updated.
*
*/
public interface TimestampSignature {
/**
*
* @param resource
* A resource related to this signature
* @return True if the current resource is different from this signature in a meaningful way
*/
boolean hasChanged(IResource resource);
/**
*
* @param resource
* Update the signature details to the given resource's signature.
*/
void update(IResource resource);
}
/**
* Provides a signature based on the modificationStamp of a resource.
*/
public class SimpleResourceTimestamp implements TimestampSignature {
private long timestamp = 0;
public SimpleResourceTimestamp(IResource resource) {
update(resource);
}
public boolean hasChanged(IResource resource) {
return timestamp != resource.getModificationStamp();
}
public void update(IResource resource) {
timestamp = resource.getModificationStamp();
}
}
/**
* Provides a signature for a project based on the modificationStamp of the (1) project, (2) the
* component manifest, and (3) the facet configuration
*/
public class ProjectTimestamp implements TimestampSignature {
private long projectTimestamp = 0;
private long componentManifestTimestamp = 0;
private long facetConfigTimestamp = 0;
public ProjectTimestamp(IProject project) {
update(project);
}
public boolean hasChanged(IResource resource) {
if (resource.getType() == IResource.PROJECT) {
IProject project = (IProject) resource;
if (projectTimestamp != project.getModificationStamp())
return true;
IFile file = project.getFile(COMPONENT_MANIFEST_PATH);
if (!file.exists() || componentManifestTimestamp != file.getModificationStamp())
return true;
file = project.getFile(FACET_CONFIG_PATH);
if (!file.exists() || facetConfigTimestamp != file.getModificationStamp())
return true;
return false;
}
return true;
}
public void update(IResource resource) {
if (resource instanceof IProject) {
IProject project = (IProject) resource;
projectTimestamp = project.getModificationStamp();
IFile file = project.getFile(COMPONENT_MANIFEST_PATH);
componentManifestTimestamp = file.getModificationStamp();
file = project.getFile(FACET_CONFIG_PATH);
facetConfigTimestamp = file.getModificationStamp();
} else {
projectTimestamp = componentManifestTimestamp = facetConfigTimestamp = IResource.NULL_STAMP;
}
}
}
}