/*******************************************************************************
* Copyright (c) 2000, 2008 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
* Oakland Software Incorporated - added getSessionProperties and getPersistentProperties
*******************************************************************************/
package org.eclipse.core.internal.resources;
import java.io.*;
import java.util.Map;
import org.eclipse.core.internal.localstore.FileStoreRoot;
import org.eclipse.core.internal.utils.*;
import org.eclipse.core.internal.watson.IElementTreeData;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.QualifiedName;
/**
* A data structure containing the in-memory state of a resource in the workspace.
*/
public class ResourceInfo implements IElementTreeData, ICoreConstants, IStringPoolParticipant {
protected static final int LOWER= 0xFFFF;
protected static final int UPPER= 0xFFFF0000;
/**
* This field stores the resource modification stamp in the lower two bytes, and the character
* set generation count in the higher two bytes.
*/
protected volatile int charsetAndContentId= 0;
/**
* The file system root that this resource is stored in
*/
protected FileStoreRoot fileStoreRoot;
/** Set of flags which reflect various states of the info (used, derived, ...). */
protected int flags= 0;
/** Local sync info */
// thread safety: (Concurrency004)
protected volatile long localInfo= I_NULL_SYNC_INFO;
/**
* This field stores the sync info generation in the lower two bytes, and the marker generation
* count in the upper two bytes.
*/
protected volatile int markerAndSyncStamp;
/** The collection of markers for this resource. */
protected MarkerSet markers= null;
/** Modification stamp */
protected long modStamp= 0;
/** Unique node identifier */
// thread safety: (Concurrency004)
protected volatile long nodeId= 0;
/**
* The properties which are maintained for the lifecycle of the workspace.
* <p>
* This field is declared as the implementing class rather than the interface so we ensure that
* we get it right since we are making certain assumptions about the object type w.r.t. casting.
*/
protected ObjectMap sessionProperties= null;
/**
* The table of sync information.
* <p>
* This field is declared as the implementing class rather than the interface so we ensure that
* we get it right since we are making certain assumptions about the object type w.r.t. casting.
*/
protected ObjectMap syncInfo= null;
/**
* Returns the integer value stored in the indicated part of this info's flags.
*/
protected static int getBits(int flags, int mask, int start) {
return (flags & mask) >> start;
}
/**
* Returns the type setting for this info. Valid values are FILE, FOLDER, PROJECT,
*/
public static int getType(int flags) {
return getBits(flags, M_TYPE, M_TYPE_START);
}
/**
* Returns true if all of the bits indicated by the mask are set.
*/
public static boolean isSet(int flags, int mask) {
return (flags & mask) == mask;
}
/**
* Clears all of the bits indicated by the mask.
*/
public void clear(int mask) {
flags&= ~mask;
}
public void clearModificationStamp() {
modStamp= IResource.NULL_STAMP;
}
public synchronized void clearSessionProperties() {
sessionProperties= null;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null; // never gets here.
}
}
public int getCharsetGenerationCount() {
return charsetAndContentId >> 16;
}
public int getContentId() {
return charsetAndContentId & LOWER;
}
public FileStoreRoot getFileStoreRoot() {
return fileStoreRoot;
}
/**
* Returns the set of flags for this info.
*/
public int getFlags() {
return flags;
}
/**
* Gets the local-relative sync information.
*/
public long getLocalSyncInfo() {
return localInfo;
}
/**
* Returns the marker generation count. The count is incremented whenever markers on the
* resource change.
*/
public int getMarkerGenerationCount() {
return markerAndSyncStamp >> 16;
}
/**
* Returns a copy of the collection of makers on this resource. <code>null</code> is returned if
* there are none.
*/
public MarkerSet getMarkers() {
return getMarkers(true);
}
/**
* Returns the collection of makers on this resource. <code>null</code> is returned if there are
* none.
*/
public MarkerSet getMarkers(boolean makeCopy) {
if (markers == null)
return null;
return makeCopy ? (MarkerSet)markers.clone() : markers;
}
public long getModificationStamp() {
return modStamp;
}
public long getNodeId() {
return nodeId;
}
/**
* Returns the property store associated with this info. The return value may be null.
*/
public Object getPropertyStore() {
return null;
}
/**
* Returns a copy of the map of this resource session properties. An empty map is returned if
* there are none.
*/
public Map getSessionProperties() {
// thread safety: (Concurrency001)
ObjectMap temp= sessionProperties;
if (temp == null)
temp= new ObjectMap(5);
else
temp= (ObjectMap)sessionProperties.clone();
return temp;
}
/**
* Returns the value of the identified session property
*/
public Object getSessionProperty(QualifiedName name) {
// thread safety: (Concurrency001)
Map temp= sessionProperties;
if (temp == null)
return null;
return temp.get(name);
}
/**
* The parameter to this method is the implementing class rather than the interface so we ensure
* that we get it right since we are making certain assumptions about the object type w.r.t.
* casting.
*/
public synchronized ObjectMap getSyncInfo(boolean makeCopy) {
if (syncInfo == null)
return null;
return makeCopy ? (ObjectMap)syncInfo.clone() : syncInfo;
}
public synchronized byte[] getSyncInfo(QualifiedName id, boolean makeCopy) {
// thread safety: (Concurrency001)
byte[] b;
if (syncInfo == null)
return null;
b= (byte[])syncInfo.get(id);
return b == null ? null : (makeCopy ? (byte[])b.clone() : b);
}
/**
* Returns the sync information generation count. The count is incremented whenever sync info on
* the resource changes.
*/
public int getSyncInfoGenerationCount() {
return markerAndSyncStamp & LOWER;
}
/**
* Returns the type setting for this info. Valid values are FILE, FOLDER, PROJECT,
*/
public int getType() {
return getType(flags);
}
/**
* Increments the charset generation count. The count is incremented whenever the encoding on
* the resource changes.
*/
public void incrementCharsetGenerationCount() {
//increment high order bits
charsetAndContentId= ((charsetAndContentId + LOWER + 1) & UPPER) + (charsetAndContentId & LOWER);
}
/**
* Mark this resource info as having changed content
*/
public void incrementContentId() {
//increment low order bits
charsetAndContentId= (charsetAndContentId & UPPER) + ((charsetAndContentId + 1) & LOWER);
}
/**
* Increments the marker generation count. The count is incremented whenever markers on the
* resource change.
*/
public void incrementMarkerGenerationCount() {
//increment high order bits
markerAndSyncStamp= ((markerAndSyncStamp + LOWER + 1) & UPPER) + (markerAndSyncStamp & LOWER);
}
/**
* Change the modification stamp to indicate that this resource has changed. The exact value of
* the stamp doesn't matter, as long as it can be used to distinguish two arbitrary resource
* generations.
*/
public void incrementModificationStamp() {
modStamp++;
}
/**
* Increments the sync information generation count. The count is incremented whenever sync info
* on the resource changes.
*/
public void incrementSyncInfoGenerationCount() {
//increment low order bits
markerAndSyncStamp= (markerAndSyncStamp & UPPER) + ((markerAndSyncStamp + 1) & LOWER);
}
/**
* Returns true if all of the bits indicated by the mask are set.
*/
public boolean isSet(int mask) {
return (flags & mask) == mask;
}
public void readFrom(int newFlags, DataInput input) throws IOException {
// The flags for this info are read by the visitor (flattener).
// See Workspace.readElement(). This allows the reader to look ahead
// and see what type of info is being loaded.
this.flags= newFlags;
localInfo= input.readLong();
nodeId= input.readLong();
charsetAndContentId= input.readInt() & LOWER;
modStamp= input.readLong();
}
/**
* Sets all of the bits indicated by the mask.
*/
public void set(int mask) {
flags|= mask;
}
/**
* Sets the value of the indicated bits to be the given value.
*/
protected void setBits(int mask, int start, int value) {
int baseMask= mask >> start;
int newValue= (value & baseMask) << start;
// thread safety: (guarantee atomic assignment)
int temp= flags;
temp&= ~mask;
temp|= newValue;
flags= temp;
}
public void setFileStoreRoot(FileStoreRoot fileStoreRoot) {
this.fileStoreRoot= fileStoreRoot;
}
/**
* Sets the flags for this info.
*/
protected void setFlags(int value) {
flags= value;
}
/**
* Sets the local-relative sync information.
*/
public void setLocalSyncInfo(long info) {
localInfo= info;
}
/**
* Sets the collection of makers for this resource. <code>null</code> is passed in if there are
* no markers.
*/
public void setMarkers(MarkerSet value) {
markers= value;
}
/**
* Sets the resource modification stamp.
*/
public void setModificationStamp(long value) {
this.modStamp= value;
}
/**
*
*/
public void setNodeId(long id) {
nodeId= id;
}
/**
* Sets the property store associated with this info. The value may be null.
*/
public void setPropertyStore(Object value) {
// needs to be implemented on subclasses
}
/**
* Sets the identified session property to the given value. If the value is null, the property
* is removed.
*/
public synchronized void setSessionProperty(QualifiedName name, Object value) {
// thread safety: (Concurrency001)
if (value == null) {
if (sessionProperties == null)
return;
ObjectMap temp= (ObjectMap)sessionProperties.clone();
temp.remove(name);
if (temp.isEmpty())
sessionProperties= null;
else
sessionProperties= temp;
} else {
ObjectMap temp= sessionProperties;
if (temp == null)
temp= new ObjectMap(5);
else
temp= (ObjectMap)sessionProperties.clone();
temp.put(name, value);
sessionProperties= temp;
}
}
/**
* The parameter to this method is the implementing class rather than the interface so we ensure
* that we get it right since we are making certain assumptions about the object type w.r.t.
* casting.
*/
protected void setSyncInfo(ObjectMap syncInfo) {
this.syncInfo= syncInfo;
}
public synchronized void setSyncInfo(QualifiedName id, byte[] value) {
if (value == null) {
//delete sync info
if (syncInfo == null)
return;
syncInfo.remove(id);
if (syncInfo.isEmpty())
syncInfo= null;
} else {
//add sync info
if (syncInfo == null)
syncInfo= new ObjectMap(5);
syncInfo.put(id, value.clone());
}
}
/**
* Sets the type for this info to the given value. Valid values are FILE, FOLDER, PROJECT
*/
public void setType(int value) {
setBits(M_TYPE, M_TYPE_START, value);
}
/* (non-Javadoc
* Method declared on IStringPoolParticipant
*/
public void shareStrings(StringPool set) {
ObjectMap map= syncInfo;
if (map != null)
map.shareStrings(set);
map= sessionProperties;
if (map != null)
map.shareStrings(set);
MarkerSet markerSet= markers;
if (markerSet != null)
markerSet.shareStrings(set);
}
public void writeTo(DataOutput output) throws IOException {
// The flags for this info are written by the visitor (flattener).
// See SaveManager.writeElement(). This allows the reader to look ahead
// and see what type of info is being loaded.
output.writeLong(localInfo);
output.writeLong(nodeId);
output.writeInt(getContentId());
output.writeLong(modStamp);
}
}