Recoded plug-in to be Foundation 1.0 and J2SE 1.3 compliant.
diff --git a/bundles/org.eclipse.core.expressions/META-INF/MANIFEST.MF b/bundles/org.eclipse.core.expressions/META-INF/MANIFEST.MF
index bdc7dc9..f8ea6c0 100644
--- a/bundles/org.eclipse.core.expressions/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.core.expressions/META-INF/MANIFEST.MF
@@ -11,3 +11,5 @@
org.eclipse.core.internal.expressions;x-internal:=true
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.1.0,4.0.0)"
Eclipse-LazyStart: true
+Bundle-RequiredExecutionEnvironment: CDC-1.0/Foundation-1.0,
+ J2SE-1.3
diff --git a/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/PropertyCache.java b/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/PropertyCache.java
index 5bbb1b7..9916215 100644
--- a/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/PropertyCache.java
+++ b/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/PropertyCache.java
@@ -10,22 +10,15 @@
*******************************************************************************/
package org.eclipse.core.internal.expressions;
-import java.util.LinkedHashMap;
-import java.util.Map.Entry;
+import org.eclipse.core.internal.expressions.util.LRUCache;
/* package */ class PropertyCache {
- private LinkedHashMap fCache;
+ private LRUCache fCache;
public PropertyCache(final int cacheSize) {
- // start with 100 elements but be able to grow until cacheSize
- fCache= new LinkedHashMap(100, 0.75f, true) {
- /** This class is not intended to be serialized. */
- private static final long serialVersionUID= 1L;
- protected boolean removeEldestEntry(Entry eldest) {
- return size() > cacheSize;
- }
- };
+ fCache= new LRUCache(100);
+ fCache.setSpaceLimit(cacheSize);
}
public Property get(Property key) {
@@ -37,6 +30,6 @@
}
public void remove(Property method) {
- fCache.remove(method);
+ fCache.removeKey(method);
}
-}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/util/LRUCache.java b/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/util/LRUCache.java
new file mode 100644
index 0000000..941abf7
--- /dev/null
+++ b/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/util/LRUCache.java
@@ -0,0 +1,506 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.core.internal.expressions.util;
+
+
+import java.text.NumberFormat;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Copied from JDT/Core to get a cache which is independent from
+ * JDK 1.4.
+ */
+public class LRUCache implements Cloneable {
+
+ /**
+ * This type is used internally by the LRUCache to represent entries
+ * stored in the cache.
+ * It is static because it does not require a pointer to the cache
+ * which contains it.
+ *
+ * @see LRUCache
+ */
+ protected static class LRUCacheEntry {
+
+ /**
+ * Hash table key
+ */
+ public Object _fKey;
+
+ /**
+ * Hash table value (an LRUCacheEntry object)
+ */
+ public Object _fValue;
+
+ /**
+ * Time value for queue sorting
+ */
+ public int _fTimestamp;
+
+ /**
+ * Cache footprint of this entry
+ */
+ public int _fSpace;
+
+ /**
+ * Previous entry in queue
+ */
+ public LRUCacheEntry _fPrevious;
+
+ /**
+ * Next entry in queue
+ */
+ public LRUCacheEntry _fNext;
+
+ /**
+ * Creates a new instance of the receiver with the provided values
+ * for key, value, and space.
+ * @param key
+ * @param value
+ * @param space
+ */
+ public LRUCacheEntry (Object key, Object value, int space) {
+ _fKey = key;
+ _fValue = value;
+ _fSpace = space;
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ * @return a string
+ */
+ public String toString() {
+
+ return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]"; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Amount of cache space used so far
+ */
+ protected int fCurrentSpace;
+
+ /**
+ * Maximum space allowed in cache
+ */
+ protected int fSpaceLimit;
+
+ /**
+ * Counter for handing out sequential timestamps
+ */
+ protected int fTimestampCounter;
+
+ /**
+ * Hash table for fast random access to cache entries
+ */
+ protected Hashtable fEntryTable;
+
+ /**
+ * Start of queue (most recently used entry)
+ */
+ protected LRUCacheEntry fEntryQueue;
+
+ /**
+ * End of queue (least recently used entry)
+ */
+ protected LRUCacheEntry fEntryQueueTail;
+
+ /**
+ * Default amount of space in the cache
+ */
+ protected static final int DEFAULT_SPACELIMIT = 100;
+ /**
+ * Creates a new cache. Size of cache is defined by
+ * <code>DEFAULT_SPACELIMIT</code>.
+ */
+ public LRUCache() {
+
+ this(DEFAULT_SPACELIMIT);
+ }
+ /**
+ * Creates a new cache.
+ * @param size Size of Cache
+ */
+ public LRUCache(int size) {
+
+ fTimestampCounter = fCurrentSpace = 0;
+ fEntryQueue = fEntryQueueTail = null;
+ fEntryTable = new Hashtable(size);
+ fSpaceLimit = size;
+ }
+ /**
+ * Returns a new cache containing the same contents.
+ *
+ * @return New copy of object.
+ */
+ public Object clone() {
+
+ LRUCache newCache = newInstance(fSpaceLimit);
+ LRUCacheEntry qEntry;
+
+ /* Preserve order of entries by copying from oldest to newest */
+ qEntry = this.fEntryQueueTail;
+ while (qEntry != null) {
+ newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+ qEntry = qEntry._fPrevious;
+ }
+ return newCache;
+ }
+ public double fillingRatio() {
+ return (fCurrentSpace) * 100.0 / fSpaceLimit;
+ }
+ /**
+ * Flushes all entries from the cache.
+ */
+ public void flush() {
+
+ fCurrentSpace = 0;
+ LRUCacheEntry entry = fEntryQueueTail; // Remember last entry
+ fEntryTable = new Hashtable(); // Clear it out
+ fEntryQueue = fEntryQueueTail = null;
+ while (entry != null) { // send deletion notifications in LRU order
+ privateNotifyDeletionFromCache(entry);
+ entry = entry._fPrevious;
+ }
+ }
+ /**
+ * Flushes the given entry from the cache. Does nothing if entry does not
+ * exist in cache.
+ *
+ * @param key Key of object to flush
+ */
+ public void flush (Object key) {
+
+ LRUCacheEntry entry;
+
+ entry = (LRUCacheEntry) fEntryTable.get(key);
+
+ /* If entry does not exist, return */
+ if (entry == null) return;
+
+ this.privateRemoveEntry (entry, false);
+ }
+ /**
+ * Answers the value in the cache at the given key.
+ * If the value is not in the cache, returns null
+ *
+ * @param key Hash table key of object to retrieve
+ * @return Retreived object, or null if object does not exist
+ */
+ public Object get(Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+
+ this.updateTimestamp (entry);
+ return entry._fValue;
+ }
+ /**
+ * Returns the amount of space that is current used in the cache.
+ * @return an int
+ */
+ public int getCurrentSpace() {
+ return fCurrentSpace;
+ }
+ /**
+ * Returns the maximum amount of space available in the cache.
+ * @return an int
+ */
+ public int getSpaceLimit() {
+ return fSpaceLimit;
+ }
+ /**
+ * Returns an Enumeration of the keys currently in the cache.
+ * @return an enumeration
+ */
+ public Enumeration keys() {
+ return fEntryTable.keys();
+ }
+ /**
+ * Ensures there is the specified amount of free space in the receiver,
+ * by removing old entries if necessary. Returns true if the requested space was
+ * made available, false otherwise.
+ *
+ * @param space Amount of space to free up
+ * @return a boolean
+ */
+ protected boolean makeSpace (int space) {
+
+ int limit;
+
+ limit = this.getSpaceLimit();
+
+ /* if space is already available */
+ if (fCurrentSpace + space <= limit) {
+ return true;
+ }
+
+ /* if entry is too big for cache */
+ if (space > limit) {
+ return false;
+ }
+
+ /* Free up space by removing oldest entries */
+ while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
+ this.privateRemoveEntry (fEntryQueueTail, false);
+ }
+ return true;
+ }
+ /**
+ * Returns a new LRUCache instance
+ * @param size the size
+ * @return a cache
+ */
+ protected LRUCache newInstance(int size) {
+ return new LRUCache(size);
+ }
+ /**
+ * Answers the value in the cache at the given key.
+ * If the value is not in the cache, returns null
+ *
+ * This function does not modify timestamps.
+ * @param key the key
+ * @return the object
+ */
+ public Object peek(Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+ return entry._fValue;
+ }
+ /**
+ * Adds an entry for the given key/value/space.
+ * @param key
+ * @param value
+ * @param space
+ */
+ protected void privateAdd (Object key, Object value, int space) {
+
+ LRUCacheEntry entry;
+
+ entry = new LRUCacheEntry(key, value, space);
+ this.privateAddEntry (entry, false);
+ }
+ /**
+ * Adds the given entry from the receiver.
+ * @param entry
+ * @param shuffle Indicates whether we are just shuffling the queue
+ * (in which case, the entry table is not modified).
+ */
+ protected void privateAddEntry (LRUCacheEntry entry, boolean shuffle) {
+
+ if (!shuffle) {
+ fEntryTable.put (entry._fKey, entry);
+ fCurrentSpace += entry._fSpace;
+ }
+
+ entry._fTimestamp = fTimestampCounter++;
+ entry._fNext = this.fEntryQueue;
+ entry._fPrevious = null;
+
+ if (fEntryQueue == null) {
+ /* this is the first and last entry */
+ fEntryQueueTail = entry;
+ } else {
+ fEntryQueue._fPrevious = entry;
+ }
+
+ fEntryQueue = entry;
+ }
+ /**
+ * An entry has been removed from the cache, for example because it has
+ * fallen off the bottom of the LRU queue.
+ * Subclasses could over-ride this to implement a persistent cache below the LRU cache.
+ * @param entry
+ */
+ protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
+ // Default is NOP.
+ }
+ /**
+ * Removes the entry from the entry queue.
+ * @param entry
+ * @param shuffle indicates whether we are just shuffling the queue
+ * (in which case, the entry table is not modified).
+ */
+ protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) {
+
+ LRUCacheEntry previous, next;
+
+ previous = entry._fPrevious;
+ next = entry._fNext;
+
+ if (!shuffle) {
+ fEntryTable.remove(entry._fKey);
+ fCurrentSpace -= entry._fSpace;
+ privateNotifyDeletionFromCache(entry);
+ }
+
+ /* if this was the first entry */
+ if (previous == null) {
+ fEntryQueue = next;
+ } else {
+ previous._fNext = next;
+ }
+
+ /* if this was the last entry */
+ if (next == null) {
+ fEntryQueueTail = previous;
+ } else {
+ next._fPrevious = previous;
+ }
+ }
+ /**
+ * Sets the value in the cache at the given key. Returns the value.
+ *
+ * @param key Key of object to add.
+ * @param value Value of object to add.
+ * @return added value.
+ */
+ public Object put(Object key, Object value) {
+
+ int newSpace, oldSpace, newTotal;
+ LRUCacheEntry entry;
+
+ /* Check whether there's an entry in the cache */
+ newSpace = spaceFor(value);
+ entry = (LRUCacheEntry) fEntryTable.get (key);
+
+ if (entry != null) {
+
+ /**
+ * Replace the entry in the cache if it would not overflow
+ * the cache. Otherwise flush the entry and re-add it so as
+ * to keep cache within budget
+ */
+ oldSpace = entry._fSpace;
+ newTotal = getCurrentSpace() - oldSpace + newSpace;
+ if (newTotal <= getSpaceLimit()) {
+ updateTimestamp (entry);
+ entry._fValue = value;
+ entry._fSpace = newSpace;
+ this.fCurrentSpace = newTotal;
+ return value;
+ } else {
+ privateRemoveEntry (entry, false);
+ }
+ }
+ if (makeSpace(newSpace)) {
+ privateAdd (key, value, newSpace);
+ }
+ return value;
+ }
+ /**
+ * Removes and returns the value in the cache for the given key.
+ * If the key is not in the cache, returns null.
+ *
+ * @param key Key of object to remove from cache.
+ * @return Value removed from cache.
+ */
+ public Object removeKey (Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+ Object value = entry._fValue;
+ this.privateRemoveEntry (entry, false);
+ return value;
+ }
+ /**
+ * Sets the maximum amount of space that the cache can store
+ *
+ * @param limit Number of units of cache space
+ */
+ public void setSpaceLimit(int limit) {
+ if (limit < fSpaceLimit) {
+ makeSpace(fSpaceLimit - limit);
+ }
+ fSpaceLimit = limit;
+ }
+ /**
+ * Returns the space taken by the given value.
+ * @param value
+ * @return an int
+ */
+ protected int spaceFor (Object value) {
+ return 1;
+ }
+
+ /**
+ * Returns a String that represents the value of this object. This method
+ * is for debugging purposes only.
+ * @return a string
+ */
+ public String toString() {
+ return
+ toStringFillingRation("LRUCache") + //$NON-NLS-1$
+ toStringContents();
+ }
+
+ /**
+ * Returns a String that represents the contents of this object. This method
+ * is for debugging purposes only.
+ * @return a string
+ */
+ protected String toStringContents() {
+ StringBuffer result = new StringBuffer();
+ int length = fEntryTable.size();
+ Object[] unsortedKeys = new Object[length];
+ String[] unsortedToStrings = new String[length];
+ Enumeration e = this.keys();
+ for (int i = 0; i < length; i++) {
+ Object key = e.nextElement();
+ unsortedKeys[i] = key;
+ unsortedToStrings[i] = key.toString();
+ }
+ ToStringSorter sorter = new ToStringSorter();
+ sorter.sort(unsortedKeys, unsortedToStrings);
+ for (int i = 0; i < length; i++) {
+ String toString = sorter.sortedStrings[i];
+ Object value = this.get(sorter.sortedObjects[i]);
+ result.append(toString);
+ result.append(" -> "); //$NON-NLS-1$
+ result.append(value);
+ result.append("\n"); //$NON-NLS-1$
+ }
+ return result.toString();
+ }
+
+ public String toStringFillingRation(String cacheName) {
+ StringBuffer buffer = new StringBuffer(cacheName);
+ buffer.append('[');
+ buffer.append(getSpaceLimit());
+ buffer.append("]: "); //$NON-NLS-1$
+ buffer.append(NumberFormat.getInstance().format(fillingRatio()));
+ buffer.append("% full"); //$NON-NLS-1$
+ return buffer.toString();
+ }
+
+ /**
+ * Updates the timestamp for the given entry, ensuring that the queue is
+ * kept in correct order. The entry must exist
+ * @param entry
+ */
+ protected void updateTimestamp (LRUCacheEntry entry) {
+
+ entry._fTimestamp = fTimestampCounter++;
+ if (fEntryQueue != entry) {
+ this.privateRemoveEntry (entry, true);
+ this.privateAddEntry (entry, true);
+ }
+ return;
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/util/ToStringSorter.java b/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/util/ToStringSorter.java
new file mode 100644
index 0000000..5cf1563
--- /dev/null
+++ b/bundles/org.eclipse.core.expressions/src/org/eclipse/core/internal/expressions/util/ToStringSorter.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.core.internal.expressions.util;
+
+/**
+ * The SortOperation takes a collection of objects and returns a sorted
+ * collection of these objects. The sorting of these objects is based on their
+ * toString(). They are sorted in alphabetical order.
+ * <p>
+ * This is a copy from JDT/Core. The copy is necessary to get an LRU cache which
+ * is independent from JDK 1.4
+ * </p>
+ */
+public class ToStringSorter {
+ Object[] sortedObjects;
+ String[] sortedStrings;
+
+ /**
+ * Returns true if stringTwo is 'greater than' stringOne This is the
+ * 'ordering' method of the sort operation.
+ * @param stringOne
+ * @param stringTwo
+ * @return a boolean
+ */
+ public boolean compare(String stringOne, String stringTwo) {
+ return stringOne.compareTo(stringTwo) < 0;
+ }
+
+ /**
+ * Sort the objects in sorted collection and return that collection.
+ * @param left
+ * @param right
+ */
+ private void quickSort(int left, int right) {
+ int originalLeft= left;
+ int originalRight= right;
+ int midIndex= (left + right) / 2;
+ String midToString= this.sortedStrings[midIndex];
+
+ do {
+ while (compare(this.sortedStrings[left], midToString))
+ left++;
+ while (compare(midToString, this.sortedStrings[right]))
+ right--;
+ if (left <= right) {
+ Object tmp= this.sortedObjects[left];
+ this.sortedObjects[left]= this.sortedObjects[right];
+ this.sortedObjects[right]= tmp;
+ String tmpToString= this.sortedStrings[left];
+ this.sortedStrings[left]= this.sortedStrings[right];
+ this.sortedStrings[right]= tmpToString;
+ left++;
+ right--;
+ }
+ } while (left <= right);
+
+ if (originalLeft < right)
+ quickSort(originalLeft, right);
+ if (left < originalRight)
+ quickSort(left, originalRight);
+ }
+
+ /**
+ * Return a new sorted collection from this unsorted collection. Sort using
+ * quick sort.
+ * @param unSortedObjects
+ * @param unsortedStrings
+ */
+ public void sort(Object[] unSortedObjects, String[] unsortedStrings) {
+ int size= unSortedObjects.length;
+ this.sortedObjects= new Object[size];
+ this.sortedStrings= new String[size];
+
+ // copy the array so can return a new sorted collection
+ System.arraycopy(unSortedObjects, 0, this.sortedObjects, 0, size);
+ System.arraycopy(unsortedStrings, 0, this.sortedStrings, 0, size);
+ if (size > 1)
+ quickSort(0, size - 1);
+ }
+}
\ No newline at end of file