243747 "Cannot find the tag library descriptor" ...
diff --git a/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF
index 2d66309..c1ce59f 100644
--- a/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jst.jsp.core; singleton:=true
-Bundle-Version: 1.2.101.qualifier
+Bundle-Version: 1.2.102.qualifier
 Bundle-Activator: org.eclipse.jst.jsp.core.internal.JSPCorePlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/ArrayMap.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/ArrayMap.java
new file mode 100644
index 0000000..507ec77
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/ArrayMap.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 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
+ *     
+ *******************************************************************************/
+package org.eclipse.jst.jsp.core.internal.java;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+/**
+ * This implementation of a hashtable maps keys to arrays
+ * to support multiple values being associated with a single
+ * key. To remove a specific entry, a key and inserted value must
+ * be provided. Removing just based on the key name will remove all
+ * values stored under that key
+ * 
+ */
+public class ArrayMap extends Hashtable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	
+	public ArrayMap(int size) {
+		super(size);
+	}
+	
+	public synchronized Object put(Object key, Object value) {
+		Object[] values = (Object[]) super.get(key);
+		Object[] newValues = null;
+		
+		if (values == null || values.length == 0)
+			newValues = new Object[1];
+		else {
+			newValues = new Object[values.length + 1];
+			System.arraycopy(values, 0, newValues, 0, values.length);
+		}
+
+		newValues[newValues.length - 1] = value;
+		return super.put(key, newValues);
+	}
+	
+	/**
+	 * Removes the first occurrence of <code>value</code> from the list 
+	 * of values associated with <code>key</code>
+	 * 
+	 * @param key the key that has <code>value</code>
+	 * @param value the specific value to remove from the key
+	 * @return The item removed from the list of values
+	 */
+	public synchronized Object remove(Object key, Object value) {
+		Object[] values = (Object[]) super.get(key);
+		Object removed = null;
+		Object[] result = null;
+		if (values != null && value != null) {
+			for (int i = 0; i < values.length; i++) {
+				if (value.equals(values[i])) {
+					removed = values[i];
+					result = new Object[values.length - 1];
+					
+					if (result.length > 0) {
+						// Copy left of value
+						System.arraycopy(values, 0, result, 0, i);
+						// Copy right of value
+						if (i < (values.length - 1))
+							System.arraycopy(values, i+1, result, i, result.length - i);
+					}
+					else
+						super.remove(key);
+					
+					break;
+				}
+			}
+		}
+		
+		if(result != null && result.length > 0)
+			super.put(key, result);
+		
+		return removed;
+	}
+	
+	public Collection values() {
+		Collection valuemaps = super.values();
+		Collection values = new ArrayList();
+		
+		for(Iterator i = valuemaps.iterator(); i.hasNext();)
+			values.addAll(Arrays.asList((Object[]) i.next()));
+		
+		return values;
+	}
+
+}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java
index 6c24aca..306829a 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * Copyright (c) 2005, 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
@@ -73,10 +73,12 @@
 import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.JSP11TLDNames;
 import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.JSP12TLDNames;
 import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache;
+import org.eclipse.jst.jsp.core.internal.java.ArrayMap;
 import org.eclipse.jst.jsp.core.internal.util.DocumentProvider;
 import org.eclipse.jst.jsp.core.internal.util.FacetModuleCoreSupport;
 import org.eclipse.wst.common.uriresolver.internal.util.URIHelper;
 import org.eclipse.wst.sse.core.internal.util.JarUtilities;
+import org.eclipse.wst.sse.core.internal.util.Sorter;
 import org.eclipse.wst.sse.core.utils.StringUtils;
 import org.eclipse.wst.xml.core.internal.XMLCorePlugin;
 import org.eclipse.wst.xml.core.internal.catalog.provisional.ICatalog;
@@ -87,6 +89,7 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import com.ibm.icu.text.Collator;
 import com.ibm.icu.util.StringTokenizer;
 
 class ProjectDescription {
@@ -475,6 +478,36 @@
 			return s.toString();
 		}
 	}
+	
+	private class TaglibSorter extends Sorter {
+		Collator collator = Collator.getInstance();
+
+		public boolean compare(Object elementOne, Object elementTwo) {
+			/**
+			 * Returns true if elementTwo is 'greater than' elementOne This is
+			 * the 'ordering' method of the sort operation. Each subclass
+			 * overides this method with the particular implementation of the
+			 * 'greater than' concept for the objects being sorted.
+			 */
+			
+			return (collator.compare(getTaglibPath((ITaglibRecord) elementOne), getTaglibPath((ITaglibRecord) elementTwo))) < 0;
+		}
+		
+		private String getTaglibPath(ITaglibRecord record) {
+			switch(record.getRecordType()) {
+				case ITaglibRecord.JAR:
+					return ((JarRecord) record).getLocation().toString();
+				case ITaglibRecord.TAGDIR:
+					return ((TagDirRecord) record).getPath().toString();
+				case ITaglibRecord.TLD:
+					return ((TLDRecord) record).getPath().toString();
+				case ITaglibRecord.URL:
+					return ((URLRecord) record).getBaseLocation();
+				default:
+					return ""; //$NON-NLS-1$
+			}
+		}
+	}
 
 	static boolean _debugIndexCreation = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jst.jsp.core/taglib/indexcreation")); //$NON-NLS-1$ //$NON-NLS-2$
 	static boolean _debugIndexTime = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jst.jsp.core/taglib/indextime")); //$NON-NLS-1$ //$NON-NLS-2$
@@ -543,6 +576,8 @@
 	ILock LOCK = Job.getJobManager().newLock();
 
 	private long time0;
+	
+	private TaglibSorter fTaglibSorter = new TaglibSorter();
 
 	ProjectDescription(IProject project, String saveStateFile) {
 		super();
@@ -1097,7 +1132,7 @@
 		String localRoot = getLocalRoot(path);
 		Hashtable implicitReferences = (Hashtable) fImplicitReferences.get(localRoot);
 		if (implicitReferences == null) {
-			implicitReferences = new Hashtable(1);
+			implicitReferences = new ArrayMap(1);
 			fImplicitReferences.put(localRoot, implicitReferences);
 		}
 		return implicitReferences;
@@ -1427,7 +1462,7 @@
 			URLRecord[] records = (URLRecord[]) record.getURLRecords().toArray(new URLRecord[0]);
 			for (int i = 0; i < records.length; i++) {
 				TaglibIndex.getInstance().addDelta(new TaglibIndexDelta(fProject, records[i], ITaglibIndexDelta.REMOVED));
-				getImplicitReferences(jar.getFullPath().toString()).remove(records[i].getURI());
+				((ArrayMap) getImplicitReferences(jar.getFullPath().toString())).remove(records[i].getURI(), records[i]);
 			}
 			if (record.has11TLD) {
 				TaglibIndex.getInstance().addDelta(new TaglibIndexDelta(fProject, record, ITaglibIndexDelta.REMOVED));
@@ -1459,7 +1494,7 @@
 		TLDRecord record = (TLDRecord) fTLDReferences.remove(tld.getFullPath().toString());
 		if (record != null) {
 			if (record.getURI() != null) {
-				getImplicitReferences(tld.getFullPath().toString()).remove(record.getURI());
+				((ArrayMap) getImplicitReferences(tld.getFullPath().toString())).remove(record.getURI(), record);
 			}
 			TaglibIndex.getInstance().addDelta(new TaglibIndexDelta(fProject, record, ITaglibIndexDelta.REMOVED));
 		}
@@ -1474,7 +1509,7 @@
 			for (int i = 0; i < records.length; i++) {
 				if (_debugIndexCreation)
 					Logger.log(Logger.INFO, "removed record for " + records[i].getURI() + "@" + records[i].path); //$NON-NLS-1$ //$NON-NLS-2$
-				getImplicitReferences(webxml.getFullPath().toString()).remove(records[i].getURI());
+				((ArrayMap) getImplicitReferences(webxml.getFullPath().toString())).remove(records[i].getURI(), records[i]);
 				TaglibIndex.getInstance().addDelta(new TaglibIndexDelta(fProject, records[i], ITaglibIndexDelta.REMOVED));
 			}
 		}
@@ -1539,7 +1574,12 @@
 				record = (ITaglibRecord) fTLDReferences.get(path);
 			}
 			if (record == null && jspVersion >= 1.2) {
-				record = (ITaglibRecord) getImplicitReferences(basePath).get(reference);
+				Object[] records = (Object[]) getImplicitReferences(basePath).get(reference);
+				if (records != null && records.length > 0) {
+					if (records.length > 1)
+						records = fTaglibSorter.sort(records);
+					record =  (ITaglibRecord) records[records.length - 1];
+				}
 			}
 
 
@@ -1593,7 +1633,12 @@
 				for (int i = 0; i < webxmls.length; i++) {
 					if (record != null)
 						continue;
-					record = (ITaglibRecord) getImplicitReferences(webxmls[i].path.toString()).get(reference);
+					Object[] records = (Object[]) getImplicitReferences(webxmls[i].path.toString()).get(reference);
+					if (records != null && records.length > 0) {
+						if (records.length > 1)
+							records = fTaglibSorter.sort(records);
+						record =  (ITaglibRecord) records[records.length - 1];
+					}
 				}
 			}
 		}
diff --git a/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF
index c96eb0c..430fdc8 100644
--- a/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.wst.sse.core; singleton:=true
-Bundle-Version: 1.1.301.qualifier
+Bundle-Version: 1.1.302.qualifier
 Bundle-Activator: org.eclipse.wst.sse.core.internal.SSECorePlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/util/Sorter.java b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/util/Sorter.java
new file mode 100644
index 0000000..e3ff42b
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/util/Sorter.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 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
+ *     Jens Lukowski/Innoopract - initial renaming/restructuring
+ *     
+ *******************************************************************************/
+package org.eclipse.wst.sse.core.internal.util;
+
+
+
+/**
+ * The SortOperation takes a collection of objects and returns a sorted
+ * collection of these objects. Concrete instances of this class provide the
+ * criteria for the sorting of the objects based on the type of the objects.
+ */
+public abstract class Sorter {
+
+	/**
+	 * Returns true if elementTwo is 'greater than' elementOne This is the
+	 * 'ordering' method of the sort operation. Each subclass overides this
+	 * method with the particular implementation of the 'greater than' concept
+	 * for the objects being sorted.
+	 */
+	public abstract boolean compare(Object elementOne, Object elementTwo);
+
+	/**
+	 * Sort the objects in sorted collection and return that collection.
+	 */
+	private Object[] quickSort(Object[] sortedCollection, int left, int right) {
+		int originalLeft = left;
+		int originalRight = right;
+		Object mid = sortedCollection[(left + right) / 2];
+
+		do {
+			while (compare(sortedCollection[left], mid))
+				left++;
+			while (compare(mid, sortedCollection[right]))
+				right--;
+			if (left <= right) {
+				Object tmp = sortedCollection[left];
+				sortedCollection[left] = sortedCollection[right];
+				sortedCollection[right] = tmp;
+				left++;
+				right--;
+			}
+		} while (left <= right);
+
+		if (originalLeft < right)
+			sortedCollection = quickSort(sortedCollection, originalLeft, right);
+		if (left < originalRight)
+			sortedCollection = quickSort(sortedCollection, left, originalRight);
+
+		return sortedCollection;
+	}
+
+	/**
+	 * Return a new sorted collection from this unsorted collection. Sort
+	 * using quick sort.
+	 */
+	public Object[] sort(Object[] unSortedCollection) {
+		int size = unSortedCollection.length;
+		Object[] sortedCollection = new Object[size];
+
+		//copy the array so can return a new sorted collection
+		System.arraycopy(unSortedCollection, 0, sortedCollection, 0, size);
+		if (size > 1)
+			quickSort(sortedCollection, 0, size - 1);
+
+		return sortedCollection;
+	}
+}