use interfaces for return types, support in-workspace paths better
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IJarRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IJarRecord.java
new file mode 100644
index 0000000..52d9e48
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IJarRecord.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 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.jst.jsp.core.internal.contentmodel;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.IPath;
+
+public interface IJarRecord extends ITaglibRecord {
+	/**
+	 * @return Returns the location.
+	 */
+	public IPath getLocation();
+
+	/**
+	 * @return Returns the recommended/default prefix if one was given.
+	 */
+	public String getPrefix();
+
+	/**
+	 * 
+	 */
+	public List getURLRecords();
+}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ITLDRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ITLDRecord.java
new file mode 100644
index 0000000..f59130c
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ITLDRecord.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 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.jst.jsp.core.internal.contentmodel;
+
+import org.eclipse.core.runtime.IPath;
+
+public interface ITLDRecord extends ITaglibRecord {
+
+	/**
+	 * @return Returns the path within the workspace.
+	 */
+	IPath getPath();
+
+	/**
+	 * @return Returns the recommended/default prefix if one was given.
+	 */
+	String getPrefix();
+
+	/**
+	 * @return Returns the uri.
+	 */
+	String getURI();
+
+}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ITagDirRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ITagDirRecord.java
new file mode 100644
index 0000000..4a275dd
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ITagDirRecord.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 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.jst.jsp.core.internal.contentmodel;
+
+public interface ITagDirRecord extends ITaglibRecord {
+
+}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IURLRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IURLRecord.java
new file mode 100644
index 0000000..9bfa584
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IURLRecord.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse 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.contentmodel;
+
+import java.net.URL;
+
+public interface IURLRecord extends ITaglibRecord {
+
+	String getBaseLocation();
+
+	/**
+	 * @return Returns the recommended/default prefix if one was given.
+	 */
+	String getPrefix();
+
+	/**
+	 * @return Returns the uri for this TLD.
+	 */
+	String getURI();
+
+	/**
+	 * @return Returns the URL to this TLD.
+	 */
+	URL getURL();
+}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IWebXMLRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IWebXMLRecord.java
new file mode 100644
index 0000000..ffc0620
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/IWebXMLRecord.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 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.jst.jsp.core.internal.contentmodel;
+
+public interface IWebXMLRecord extends ITaglibRecord {
+
+}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/JarRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/JarRecord.java
deleted file mode 100644
index f2eb150..0000000
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/JarRecord.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2001, 2004 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.contentmodel;
-
-import java.util.List;
-
-import org.eclipse.core.runtime.IPath;
-
-/**
- * TaglibRecord for a JAR file, also includes the records for any .tld files
- * contained within it.
- */
-
-public class JarRecord implements ITaglibRecord {
-	IPath location;
-	String prefix;
-	List urlRecords;
-	boolean has11TLD;
-
-	public boolean equals(Object obj) {
-		if (!(obj instanceof JarRecord))
-			return false;
-		return ((JarRecord) obj).location.equals(location);
-	}
-
-	/**
-	 * @return Returns the location.
-	 */
-	public IPath getLocation() {
-		return location;
-	}
-
-	/**
-	 * @return Returns the recommended/default prefix if one was given.
-	 */
-	public String getPrefix() {
-		return prefix;
-	}
-
-	public int getRecordType() {
-		return ITaglibRecord.JAR;
-	}
-
-	/**
-	 * 
-	 */
-	public List getURLRecords() {
-		return urlRecords;
-	}
-
-	public String toString() {
-		return "JarRecord: " + location + " <-> " + urlRecords; //$NON-NLS-1$ //$NON-NLS-2$
-	}
-}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ProjectDescription.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ProjectDescription.java
index 9fd1cf3..d07be85 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ProjectDescription.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ProjectDescription.java
@@ -11,6 +11,10 @@
  *******************************************************************************/
 package org.eclipse.jst.jsp.core.internal.contentmodel;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
@@ -85,10 +89,10 @@
 				}
 				else if (resource.getName().equals(WEB_XML) && resource.getParent().getName().equals(WEB_INF)) {
 					if (delta.getKind() == IResourceDelta.REMOVED) {
-						removeServlets(resource);
+						removeWebXML(resource);
 					}
 					else {
-						updateServlets(resource, delta.getKind());
+						updateWebXML(resource, delta.getKind());
 					}
 				}
 			}
@@ -109,7 +113,7 @@
 					updateTagDir(proxy.requestResource(), ITaglibRecordEvent.ADDED);
 				}
 				else if (proxy.getName().equals(WEB_XML) && proxy.requestResource().getParent().getName().equals(WEB_INF)) {
-					updateServlets(proxy.requestResource(), ITaglibRecordEvent.ADDED);
+					updateWebXML(proxy.requestResource(), ITaglibRecordEvent.ADDED);
 				}
 			}
 			String name = proxy.getName();
@@ -117,9 +121,99 @@
 		}
 	}
 
-	class TaglibInfo {
+	static class JarRecord implements IJarRecord {
+		boolean has11TLD;
+		IPath location;
+		TaglibInfo info;
+		List urlRecords;
+
+		public boolean equals(Object obj) {
+			if (!(obj instanceof JarRecord))
+				return false;
+			return ((JarRecord) obj).location.equals(location);
+		}
+
+		/**
+		 * @return Returns the location.
+		 */
+		public IPath getLocation() {
+			return location;
+		}
+
+		/**
+		 * @return Returns the recommended/default prefix if one was given.
+		 */
+		public String getPrefix() {
+			if (info == null)
+				return null;
+			return info.prefix;
+		}
+
+		public int getRecordType() {
+			return ITaglibRecord.JAR;
+		}
+
+		/**
+		 * 
+		 */
+		public List getURLRecords() {
+			return urlRecords;
+		}
+
+		public String toString() {
+			return "JarRecord: " + location + " <-> " + urlRecords; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
+	static class TagDirRecord implements ITagDirRecord {
+		IPath location;
+		String shortName;
+		// a List holding Strings of .tag and .tagx filenames relative to the
+		// tagdir's location
+		List tags = new ArrayList(0);
+
+		public boolean equals(Object obj) {
+			if (!(obj instanceof TagDirRecord))
+				return false;
+			return ((TagDirRecord) obj).location.equals(location);
+		}
+
+		/**
+		 * @return Returns the location.
+		 */
+		public IPath getLocation() {
+			return location;
+		}
+
+		public int getRecordType() {
+			return ITaglibRecord.TAGDIR;
+		}
+
+		/**
+		 * @return Returns the shortName.
+		 */
+		public String getShortName() {
+			return shortName;
+		}
+
+		/**
+		 * @return Returns the tags.
+		 */
+		public String[] getTags() {
+			return (String[]) tags.toArray(new String[tags.size()]);
+		}
+
+		public String toString() {
+			return "TagdirRecord: " + location + " <-> " + shortName; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
+	static class TaglibInfo {
 		String prefix;
 		String uri;
+		float jspVersion;
+		String smallIcon;
+		String largeIcon;
 	}
 
 	class TaglibRecordEvent implements ITaglibRecordEvent {
@@ -159,6 +253,140 @@
 		}
 	}
 
+	static class TLDRecord implements ITLDRecord {
+		IPath path;
+		TaglibInfo info;
+
+		public boolean equals(Object obj) {
+			if (!(obj instanceof TLDRecord))
+				return false;
+			return ((TLDRecord) obj).path.equals(path);
+		}
+
+		public IPath getPath() {
+			return path;
+		}
+
+		public String getPrefix() {
+			if (info == null)
+				return null;
+			return info.prefix;
+		}
+
+		public int getRecordType() {
+			return ITaglibRecord.TLD;
+		}
+
+		/**
+		 * @return Returns the uri.
+		 */
+		public String getURI() {
+			if (info == null)
+				return null;
+			return info.uri;
+		}
+
+		public String toString() {
+			return "TLDRecord: " + path + " <-> " + getURI(); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
+	static class URLRecord implements IURLRecord {
+		String baseLocation;
+		TaglibInfo info;
+		URL url;
+
+		public URLRecord() {
+			super();
+		}
+
+		public boolean equals(Object obj) {
+			if (!(obj instanceof URLRecord))
+				return false;
+			return ((URLRecord) obj).baseLocation.equals(baseLocation) || ((URLRecord) obj).getURI().equals(getURI()) || ((URLRecord) obj).url.equals(url);
+		}
+
+		public String getBaseLocation() {
+			return baseLocation;
+		}
+
+		/**
+		 * @return Returns the recommended/default prefix if one was given.
+		 */
+		public String getPrefix() {
+			if (info == null)
+				return null;
+			return info.prefix;
+		}
+
+		public int getRecordType() {
+			return ITaglibRecord.URL;
+		}
+
+		/**
+		 * @return Returns the uri.
+		 */
+		public String getURI() {
+			if (info == null)
+				return "";
+			return info.uri;
+		}
+
+		/**
+		 * @return Returns the URL.
+		 */
+		public URL getURL() {
+			return url;
+		}
+
+		public String toString() {
+			return "URLRecord: " + baseLocation + " <-> " + getURI(); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
+	static class WebXMLRecord implements IWebXMLRecord {
+		IPath path;
+		TaglibInfo info;
+		List tldRecords = new ArrayList(0);
+
+		public boolean equals(Object obj) {
+			if (!(obj instanceof WebXMLRecord))
+				return false;
+			return ((WebXMLRecord) obj).path.equals(path);
+		}
+
+		/**
+		 * @return Returns the recommended/default prefix if one was given.
+		 */
+		public String getPrefix() {
+			if (info == null)
+				return null;
+			return info.prefix;
+		}
+
+		public int getRecordType() {
+			return ITaglibRecord.WEB_XML;
+		}
+
+		/**
+		 * 
+		 */
+		public List getTLDRecords() {
+			return tldRecords;
+		}
+
+		/**
+		 * @return Returns the webxml.
+		 */
+		public IPath getWebXML() {
+			return path;
+		}
+
+		public String toString() {
+			return "WebXMLRecord: " + path + " " + tldRecords; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
 	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$
 
@@ -182,13 +410,13 @@
 	Hashtable fImplicitReferences;
 	Hashtable fJARReferences;
 	IProject fProject;
-	Hashtable fServletReferences;
 	Hashtable fTagDirReferences;
-
 	Hashtable fTLDReferences;
 
 	IResourceDeltaVisitor fVisitor;
 
+	Hashtable fWebXMLReferences;
+
 	private long time0;
 
 	ProjectDescription(IProject project) {
@@ -199,7 +427,7 @@
 		fJARReferences = new Hashtable(0);
 		fTagDirReferences = new Hashtable(0);
 		fTLDReferences = new Hashtable(0);
-		fServletReferences = new Hashtable(0);
+		fWebXMLReferences = new Hashtable(0);
 		fImplicitReferences = new Hashtable(0);
 	}
 
@@ -267,15 +495,14 @@
 	 */
 	private TLDRecord createTLDRecord(IResource tld) {
 		TLDRecord record = new TLDRecord();
-		record.location = tld.getLocation();
+		record.path = tld.getLocation();
 		InputStream contents = null;
 		try {
 			contents = ((IFile) tld).getContents(true);
-			String baseLocation = record.location.toString();
+			String baseLocation = record.path.toString();
 			TaglibInfo info = extractInfo(baseLocation, contents);
 			if (info != null) {
-				record.uri = info.uri;
-				record.prefix = info.prefix;
+				record.info = info;
 			}
 		}
 		catch (CoreException e) {
@@ -295,44 +522,54 @@
 	}
 
 	private TaglibInfo extractInfo(String baseLocation, InputStream tldContents) {
-		TaglibInfo info = null;
-		DocumentProvider provider = new DocumentProvider();
-		provider.setInputStream(tldContents);
-		provider.setValidating(false);
-		provider.setRootElementName(JSP12TLDNames.TAGLIB);
-		provider.setBaseReference(baseLocation);
-		Node child = provider.getRootElement();
-		if (child == null || child.getNodeType() != Node.ELEMENT_NODE || !child.getNodeName().equals(JSP12TLDNames.TAGLIB)) {
-			return null;
-		}
-		child = child.getFirstChild();
-		while (child != null) {
-			if (child.getNodeType() == Node.ELEMENT_NODE) {
-				if (child.getNodeName().equals(JSP12TLDNames.URI)) {
-					if (info == null) {
-						info = new TaglibInfo();
-					}
-					info.uri = getContents(child);
-				}
-				else if (child.getNodeName().equals(JSP12TLDNames.SHORT_NAME)) {
-					if (info == null) {
-						info = new TaglibInfo();
-					}
-					info.prefix = getContents(child);
-				}
+		TaglibInfo info = new TaglibInfo();
+		if (tldContents != null) {
+			DocumentProvider provider = new DocumentProvider();
+			provider.setInputStream(tldContents);
+			provider.setValidating(false);
+			provider.setRootElementName(JSP12TLDNames.TAGLIB);
+			provider.setBaseReference(baseLocation);
+			Node child = provider.getRootElement();
+			if (child == null || child.getNodeType() != Node.ELEMENT_NODE || !child.getNodeName().equals(JSP12TLDNames.TAGLIB)) {
+				return null;
 			}
-			child = child.getNextSibling();
+			child = child.getFirstChild();
+			while (child != null) {
+				if (child.getNodeType() == Node.ELEMENT_NODE) {
+					if (child.getNodeName().equals(JSP12TLDNames.URI)) {
+						info.uri = getContents(child);
+					}
+					else if (child.getNodeName().equals(JSP12TLDNames.SHORT_NAME)) {
+						info.prefix = getContents(child);
+					}
+					else if (child.getNodeName().equals(JSP12TLDNames.JSP_VERSION)) {
+						try {
+							info.jspVersion = Float.parseFloat(getContents(child));
+						}
+						catch (NumberFormatException e) {
+							info.jspVersion = 0;
+						}
+					}
+					else if (child.getNodeName().equals(JSP12TLDNames.SMALL_ICON)) {
+						info.smallIcon = getContents(child);
+					}
+					else if (child.getNodeName().equals(JSP12TLDNames.LARGE_ICON)) {
+						info.largeIcon = getContents(child);
+					}
+				}
+				child = child.getNextSibling();
+			}
 		}
 		return info;
 	}
 
 	synchronized List getAvailableTaglibRecords(IPath path) {
 		Collection implicitReferences = getImplicitReferences(path.toString()).values();
-		List records = new ArrayList(fTLDReferences.size() + fTagDirReferences.size() + fJARReferences.size() + fServletReferences.size());
+		List records = new ArrayList(fTLDReferences.size() + fTagDirReferences.size() + fJARReferences.size() + fWebXMLReferences.size());
 		records.addAll(fTLDReferences.values());
 		records.addAll(fTagDirReferences.values());
 		records.addAll(_getJSP11JarReferences(fJARReferences.values()));
-		records.addAll(fServletReferences.values());
+		records.addAll(fWebXMLReferences.values());
 		records.addAll(fClasspathReferences.values());
 		records.addAll(implicitReferences);
 		return records;
@@ -457,7 +694,7 @@
 		fTLDReferences.clear();
 		fJARReferences.clear();
 		fTagDirReferences.clear();
-		fServletReferences.clear();
+		fWebXMLReferences.clear();
 		try {
 			fProject.accept(new Indexer(), 0);
 		}
@@ -587,21 +824,6 @@
 		}
 	}
 
-	void removeServlets(IResource webxml) {
-		if (_debugIndexCreation)
-			System.out.println("removing records for " + webxml.getFullPath()); //$NON-NLS-1$
-		ServletRecord record = (ServletRecord) fServletReferences.remove(webxml.getLocation().toString());
-		if (record != null) {
-			TLDRecord[] records = (TLDRecord[]) record.getTLDRecords().toArray(new TLDRecord[0]);
-			for (int i = 0; i < records.length; i++) {
-				if (_debugIndexCreation)
-					System.out.println("removed record for " + records[i].uri + "@" + records[i].location); //$NON-NLS-1$ //$NON-NLS-2$
-				getImplicitReferences(webxml.getFullPath().toString()).remove(records[i].getURI());
-			}
-			TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(record, ITaglibRecordEvent.REMOVED));
-		}
-	}
-
 	void removeTagDir(IResource tagFile) {
 		// IContainer tagdir = tagFile.getParent();
 		// String tagdirLocation = tagdir.getFullPath().toString();
@@ -613,8 +835,23 @@
 			System.out.println("removing record for " + tld.getFullPath()); //$NON-NLS-1$
 		TLDRecord record = (TLDRecord) fTLDReferences.remove(tld.getFullPath());
 		if (record != null) {
-			if (record.uri != null) {
-				getImplicitReferences(tld.getFullPath().toString()).remove(record.uri);
+			if (record.getURI() != null) {
+				getImplicitReferences(tld.getFullPath().toString()).remove(record.getURI());
+			}
+			TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(record, ITaglibRecordEvent.REMOVED));
+		}
+	}
+
+	void removeWebXML(IResource webxml) {
+		if (_debugIndexCreation)
+			System.out.println("removing records for " + webxml.getFullPath()); //$NON-NLS-1$
+		WebXMLRecord record = (WebXMLRecord) fWebXMLReferences.remove(webxml.getLocation().toString());
+		if (record != null) {
+			TLDRecord[] records = (TLDRecord[]) record.getTLDRecords().toArray(new TLDRecord[0]);
+			for (int i = 0; i < records.length; i++) {
+				if (_debugIndexCreation)
+					System.out.println("removed record for " + records[i].getURI() + "@" + records[i].path); //$NON-NLS-1$ //$NON-NLS-2$
+				getImplicitReferences(webxml.getFullPath().toString()).remove(records[i].getURI());
 			}
 			TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(record, ITaglibRecordEvent.REMOVED));
 		}
@@ -641,7 +878,7 @@
 		}
 		// order dictated by JSP spec 2.0 section 7.2.3
 		if (record == null) {
-			record = (ITaglibRecord) fServletReferences.get(path);
+			record = (ITaglibRecord) fWebXMLReferences.get(path);
 		}
 		if (record == null) {
 			record = (ITaglibRecord) fJARReferences.get(path);
@@ -680,15 +917,14 @@
 
 					if (info != null && info.uri != null && info.uri.length() > 0) {
 						URLRecord record = new URLRecord();
-						record.uri = info.uri;
-						record.prefix = info.prefix;
+						record.info = info;
 						record.baseLocation = libraryLocation;
 						try {
 							record.url = new URL("jar:file:" + libraryLocation + "!/" + entries[i]); //$NON-NLS-1$ //$NON-NLS-2$
 							libraryRecord.urlRecords.add(record);
-							fClasspathReferences.put(record.uri, record);
+							fClasspathReferences.put(record.getURI(), record);
 							if (_debugIndexCreation)
-								System.out.println("created record for " + record.uri + "@" + record.getURL()); //$NON-NLS-1$ //$NON-NLS-2$
+								System.out.println("created record for " + record.getURI() + "@" + record.getURL()); //$NON-NLS-1$ //$NON-NLS-2$
 						}
 						catch (MalformedURLException e) {
 							// don't record this URI
@@ -724,15 +960,14 @@
 
 					if (info != null && info.uri != null && info.uri.length() > 0) {
 						URLRecord record = new URLRecord();
-						record.uri = info.uri;
-						record.prefix = info.prefix;
+						record.info = info;
 						record.baseLocation = jarLocationString;
 						try {
 							record.url = new URL("jar:file:" + jarLocationString + "!/" + entries[i]); //$NON-NLS-1$ //$NON-NLS-2$
 							jarRecord.urlRecords.add(record);
-							getImplicitReferences(jar.getFullPath().toString()).put(record.uri, record);
+							getImplicitReferences(jar.getFullPath().toString()).put(record.getURI(), record);
 							if (_debugIndexCreation)
-								System.out.println("created record for " + record.uri + "@" + record.getURL()); //$NON-NLS-1$ //$NON-NLS-2$
+								System.out.println("created record for " + record.getURI() + "@" + record.getURL()); //$NON-NLS-1$ //$NON-NLS-2$
 						}
 						catch (MalformedURLException e) {
 							// don't record this URI
@@ -750,7 +985,33 @@
 		TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(jarRecord, deltaKind));
 	}
 
-	void updateServlets(IResource webxml, int deltaKind) {
+	void updateTagDir(IResource tagFile, int deltaKind) {
+		return;
+		/**
+		 * Make sure the tag file is n a WEB-INF/tags folder because of the
+		 * shortname computation requirements
+		 */
+		// if ((tagFile.getType() & IResource.FOLDER) > 0 ||
+		// tagFile.getFullPath().toString().indexOf("WEB-INF/tags") < 0)
+		// return;
+		// TagDirRecord record = createTagdirRecord(tagFile);
+		// if (record != null) {
+		// record.tags.add(tagFile.getName());
+		// }
+	}
+
+	void updateTLD(IResource tld, int deltaKind) {
+		if (_debugIndexCreation)
+			System.out.println("creating record for " + tld.getFullPath()); //$NON-NLS-1$
+		TLDRecord record = createTLDRecord(tld);
+		fTLDReferences.put(tld.getFullPath().toString(), record);
+		if (record.getURI() != null) {
+			getImplicitReferences(tld.getFullPath().toString()).put(record.getURI(), record);
+		}
+		TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(record, deltaKind));
+	}
+
+	void updateWebXML(IResource webxml, int deltaKind) {
 		if (webxml.getType() != IResource.FILE)
 			return;
 		InputStream webxmlContents = null;
@@ -780,53 +1041,82 @@
 		if (_debugIndexCreation)
 			System.out.println("creating records for " + webxml.getFullPath()); //$NON-NLS-1$
 
-		ServletRecord servletRecord = new ServletRecord();
-		servletRecord.location = webxml.getFullPath();
-		fServletReferences.put(servletRecord.getWebXML().toString(), servletRecord);
+		WebXMLRecord servletRecord = new WebXMLRecord();
+		servletRecord.path = webxml.getFullPath();
+		fWebXMLReferences.put(servletRecord.getWebXML().toString(), servletRecord);
 		NodeList taglibs = document.getElementsByTagName(JSP12TLDNames.TAGLIB);
 		for (int i = 0; i < taglibs.getLength(); i++) {
 			String uri = readTextofChild(taglibs.item(i), "taglib-uri").trim(); //$NON-NLS-1$
 			// specified location is relative to root of the webapp
 			String location = readTextofChild(taglibs.item(i), "taglib-location").trim(); //$NON-NLS-1$
 			TLDRecord record = new TLDRecord();
-			record.uri = uri;
 			if (location.startsWith("/")) { //$NON-NLS-1$
-				record.location = new Path(getLocalRoot(webxml.getFullPath().toString()) + location);
+				record.path = new Path(getLocalRoot(webxml.getFullPath().toString()) + location);
 			}
 			else {
-				record.location = new Path(URIHelper.normalize(location, webxml.getFullPath().toString(), getLocalRoot(webxml.getLocation().toString())));
+				record.path = new Path(URIHelper.normalize(location, webxml.getFullPath().toString(), getLocalRoot(webxml.getLocation().toString())));
 			}
+			TaglibInfo info = extractInfo(record.path.toString(), getContents(record.path));
+			info.uri = uri;
+			record.info = info;
 			servletRecord.tldRecords.add(record);
 			getImplicitReferences(webxml.getFullPath().toString()).put(uri, record);
 			if (_debugIndexCreation)
-				System.out.println("created record for " + uri + "@" + record.location); //$NON-NLS-1$ //$NON-NLS-2$
+				System.out.println("created record for " + uri + "@" + record.path); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 		TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(servletRecord, deltaKind));
 	}
 
-	void updateTagDir(IResource tagFile, int deltaKind) {
-		return;
-		/**
-		 * Make sure the tag file is n a WEB-INF/tags folder because of the
-		 * shortname computation requirements
-		 */
-		// if ((tagFile.getType() & IResource.FOLDER) > 0 ||
-		// tagFile.getFullPath().toString().indexOf("WEB-INF/tags") < 0)
-		// return;
-		// TagDirRecord record = createTagdirRecord(tagFile);
-		// if (record != null) {
-		// record.tags.add(tagFile.getName());
-		// }
-	}
+	private InputStream getContents(IPath path) {
+		InputStream contents = null;
+		InputStream input = null;
+		if (path.segmentCount() > 1) {
+			IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
+			if (file != null && file.exists()) {
+				try {
+					input = file.getContents(true);
+				}
+				catch (CoreException e) {
+				}
+			}
+			else {
+				try {
+					input = new FileInputStream(path.toOSString());
+				}
+				catch (FileNotFoundException e) {
+				}
+			}
+			if (input != null) {
+				try {
+					int c;
+					ByteArrayOutputStream buffer = null;
 
-	void updateTLD(IResource tld, int deltaKind) {
-		if (_debugIndexCreation)
-			System.out.println("creating record for " + tld.getFullPath()); //$NON-NLS-1$
-		TLDRecord record = createTLDRecord(tld);
-		fTLDReferences.put(tld.getFullPath().toString(), record);
-		if (record.uri != null) {
-			getImplicitReferences(tld.getFullPath().toString()).put(record.uri, record);
+					buffer = new ByteArrayOutputStream();
+
+					// array dim restriction?
+					byte bytes[] = new byte[2048];
+					while ((c = input.read(bytes)) >= 0) {
+						buffer.write(bytes, 0, c);
+					}
+					contents = new ByteArrayInputStream(buffer.toByteArray());
+				}
+				catch (IOException e) {
+					// 
+				}
+				finally {
+					if (input != null) {
+						try {
+							input.close();
+						}
+						catch (IOException e) {
+						}
+					}
+				}
+			}
 		}
-		TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(record, deltaKind));
+		if (contents == null) {
+			contents = new ByteArrayInputStream(new byte[0]);
+		}
+		return contents;
 	}
 }
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ServletRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ServletRecord.java
deleted file mode 100644
index 07e6182..0000000
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/ServletRecord.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2001, 2004 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.contentmodel;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.core.runtime.IPath;
-
-/**
- * TaglibRecord for a taglib mapping from a web.xml file
- */
-
-public class ServletRecord implements ITaglibRecord {
-	IPath location;
-	String prefix;
-	List tldRecords = new ArrayList(0);
-
-	public boolean equals(Object obj) {
-		if (!(obj instanceof ServletRecord))
-			return false;
-		return ((ServletRecord) obj).location.equals(location);
-	}
-
-	/**
-	 * @return Returns the recommended/default prefix if one was given.
-	 */
-	public String getPrefix() {
-		return prefix;
-	}
-
-	public int getRecordType() {
-		return ITaglibRecord.WEB_XML;
-	}
-
-	/**
-	 * 
-	 */
-	public List getTLDRecords() {
-		return tldRecords;
-	}
-
-	/**
-	 * @return Returns the webxml.
-	 */
-	public IPath getWebXML() {
-		return location;
-	}
-
-	public String toString() {
-		return "ServletRecord: " + location + tldRecords; //$NON-NLS-1$
-	}
-}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TLDRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TLDRecord.java
deleted file mode 100644
index a1befed..0000000
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TLDRecord.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2001, 2004 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.contentmodel;
-
-import org.eclipse.core.runtime.IPath;
-
-
-/**
- * TaglibRecord for a standalone .tld file
- */
-public class TLDRecord implements ITaglibRecord {
-	IPath location;
-	String prefix;
-	String uri;
-
-	public boolean equals(Object obj) {
-		if (!(obj instanceof TLDRecord))
-			return false;
-		return ((TLDRecord) obj).location.equals(location);
-	}
-
-	/**
-	 * @return Returns the filesystem location.
-	 */
-	public IPath getLocation() {
-		return location;
-	}
-
-	/**
-	 * @return Returns the recommended/default prefix if one was given.
-	 */
-	public String getPrefix() {
-		return prefix;
-	}
-
-	public int getRecordType() {
-		return ITaglibRecord.TLD;
-	}
-
-	/**
-	 * @return Returns the uri.
-	 */
-	public String getURI() {
-		return uri;
-	}
-
-	public String toString() {
-		return "TLDRecord: " + location + " <-> " + uri; //$NON-NLS-1$ //$NON-NLS-2$
-	}
-}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TagDirRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TagDirRecord.java
deleted file mode 100644
index 2370c21..0000000
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TagDirRecord.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2001, 2004 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.contentmodel;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.core.runtime.IPath;
-
-/**
- * TaglibRecord for a directory tag/tagx files
- */
-public class TagDirRecord implements ITaglibRecord {
-	IPath location;
-	String shortName;
-	// a List holding Strings of .tag and .tagx filenames relative to the
-	// tagdir's location
-	List tags = new ArrayList(0);
-
-	public boolean equals(Object obj) {
-		if (!(obj instanceof TagDirRecord))
-			return false;
-		return ((TagDirRecord) obj).location.equals(location);
-	}
-
-	/**
-	 * @return Returns the location.
-	 */
-	public IPath getLocation() {
-		return location;
-	}
-
-	public int getRecordType() {
-		return ITaglibRecord.TAGDIR;
-	}
-
-	/**
-	 * @return Returns the shortName.
-	 */
-	public String getShortName() {
-		return shortName;
-	}
-
-	/**
-	 * @return Returns the tags.
-	 */
-	public String[] getTags() {
-		return (String[]) tags.toArray(new String[tags.size()]);
-	}
-
-	public String toString() {
-		return "TagdirRecord: " + location + " <-> " + shortName; //$NON-NLS-1$ //$NON-NLS-2$
-	}
-}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TaglibIndex.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TaglibIndex.java
index 82326f2..906c349 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TaglibIndex.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/TaglibIndex.java
@@ -320,12 +320,12 @@
 			else {
 				switch (result.getRecordType()) {
 					case (ITaglibRecord.TLD) : {
-						TLDRecord record = (TLDRecord) result;
-						System.out.println("TaglibIndex resolved " + basePath + ":" + reference + " = " + record.getLocation()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+						ITLDRecord record = (ITLDRecord) result;
+						System.out.println("TaglibIndex resolved " + basePath + ":" + reference + " = " + record.getPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 					}
 						break;
 					case (ITaglibRecord.JAR) : {
-						JarRecord record = (JarRecord) result;
+						IJarRecord record = (IJarRecord) result;
 						System.out.println("TaglibIndex resolved " + basePath + ":" + reference + " = " + record.getLocation()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 					}
 						break;
@@ -333,7 +333,7 @@
 					}
 						break;
 					case (ITaglibRecord.URL) : {
-						URLRecord record = (URLRecord) result;
+						IURLRecord record = (IURLRecord) result;
 						System.out.println("TaglibIndex resolved " + basePath + ":" + reference + " = " + record.getURL()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 					}
 						break;
@@ -436,7 +436,7 @@
 		}
 	}
 
-	private ITaglibRecord internalResolve(String basePath, String reference, boolean crossProjects) {
+	private ITaglibRecord internalResolve(String basePath, final String reference, boolean crossProjects) {
 		IProject project = null;
 		ITaglibRecord resolved = null;
 		IFile baseResource = FileBuffers.getWorkspaceFileAtLocation(new Path(basePath));
@@ -449,11 +449,25 @@
 			// try simple file support outside of the workspace
 			File baseFile = FileBuffers.getSystemFileAtLocation(new Path(basePath));
 			if (baseFile != null) {
-				String normalizedReference = URIHelper.normalize(reference, basePath, "/"); //$NON-NLS-1$
+				final String normalizedReference = URIHelper.normalize(reference, basePath, "/"); //$NON-NLS-1$
 				if (normalizedReference != null) {
-					TLDRecord record = new TLDRecord();
-					record.location = new Path(normalizedReference);
-					record.uri = reference;
+					ITLDRecord record = new ITLDRecord() {
+						public int getRecordType() {
+							return ITaglibRecord.TLD;
+						}
+
+						public String getURI() {
+							return reference;
+						}
+
+						public String getPrefix() {
+							return null;
+						}
+
+						public IPath getPath() {
+							return new Path(normalizedReference);
+						}
+					};
 					resolved = record;
 				}
 			}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/URLRecord.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/URLRecord.java
deleted file mode 100644
index 1f84bd5..0000000
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/URLRecord.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2001, 2004 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.contentmodel;
-
-import java.net.URL;
-
-/**
- * TaglibRecord for a descriptor only locatable using a URL (such as one
- * buried within a .jar file)
- */
-public class URLRecord implements ITaglibRecord {
-	String baseLocation;
-	String prefix;
-	String uri;
-	URL url;
-
-	public URLRecord() {
-		super();
-	}
-
-	public boolean equals(Object obj) {
-		if (!(obj instanceof URLRecord))
-			return false;
-		return ((URLRecord) obj).baseLocation.equals(baseLocation) || ((URLRecord) obj).uri.equals(uri) || ((URLRecord) obj).url.equals(url);
-	}
-
-	public String getBaseLocation() {
-		return baseLocation;
-	}
-
-	/**
-	 * @return Returns the recommended/default prefix if one was given.
-	 */
-	public String getPrefix() {
-		return prefix;
-	}
-
-	public int getRecordType() {
-		return ITaglibRecord.URL;
-	}
-
-	/**
-	 * @return Returns the uri.
-	 */
-	public String getURI() {
-		return uri;
-	}
-
-	/**
-	 * @return Returns the URL.
-	 */
-	public URL getURL() {
-		return url;
-	}
-
-	public String toString() {
-		return "URLRecord: " + baseLocation + " <-> " + uri; //$NON-NLS-1$ //$NON-NLS-2$
-	}
-}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/CMDocumentFactoryTLD.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/CMDocumentFactoryTLD.java
index 6cb45b9..4426080 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/CMDocumentFactoryTLD.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/CMDocumentFactoryTLD.java
@@ -17,11 +17,13 @@
 import java.net.URL;
 import java.net.URLConnection;
 
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.jst.jsp.core.internal.contentmodel.IJarRecord;
+import org.eclipse.jst.jsp.core.internal.contentmodel.ITLDRecord;
 import org.eclipse.jst.jsp.core.internal.contentmodel.ITaglibRecord;
-import org.eclipse.jst.jsp.core.internal.contentmodel.JarRecord;
-import org.eclipse.jst.jsp.core.internal.contentmodel.TLDRecord;
-import org.eclipse.jst.jsp.core.internal.contentmodel.URLRecord;
+import org.eclipse.jst.jsp.core.internal.contentmodel.IURLRecord;
 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.contentmodel.tld.provisional.JSP20TLDNames;
@@ -606,24 +608,27 @@
 		CMDocumentImpl document = null;
 		switch (reference.getRecordType()) {
 			case (ITaglibRecord.TLD) : {
-				TLDRecord record = (TLDRecord) reference;
-				document = (CMDocumentImpl) buildCMDocumentFromFile(record.getLocation().toString());
-				if (_debug && document != null && document.getElements().getLength() == 0) {
-					System.out.println("failure parsing " + record.getLocation()); //$NON-NLS-1$
-				}
+				ITLDRecord record = (ITLDRecord) reference;
+				IResource file = ResourcesPlugin.getWorkspace().getRoot().getFile(record.getPath());
+				if (file.getLocation() != null) {
+					document = (CMDocumentImpl) buildCMDocumentFromFile(file.getLocation().toString());
+					if (_debug && document != null && document.getElements().getLength() == 0) {
+						System.out.println("failure parsing " + record.getPath()); //$NON-NLS-1$
+					}
 
-				if (document.getSmallIcon() != null) {
-					String iconPath = URIHelper.normalize(((TLDDocument) document).getSmallIcon(), record.getLocation().toString(), "/"); //$NON-NLS-1$
-					document.setProperty(JSP12TLDNames.SMALL_ICON, "file:" + iconPath); //$NON-NLS-1$
-				}
-				if (document.getLargeIcon() != null) {
-					String iconPath = URIHelper.normalize(((TLDDocument) document).getLargeIcon(), record.getLocation().toString(), "/"); //$NON-NLS-1$
-					document.setProperty(JSP12TLDNames.LARGE_ICON, "file:" + iconPath); //$NON-NLS-1$
+					if (document.getSmallIcon() != null) {
+						String iconPath = URIHelper.normalize(((TLDDocument) document).getSmallIcon(), file.getLocation().toString(), "/"); //$NON-NLS-1$
+						document.setProperty(JSP12TLDNames.SMALL_ICON, "file:" + iconPath); //$NON-NLS-1$
+					}
+					if (document.getLargeIcon() != null) {
+						String iconPath = URIHelper.normalize(((TLDDocument) document).getLargeIcon(), file.getLocation().toString(), "/"); //$NON-NLS-1$
+						document.setProperty(JSP12TLDNames.LARGE_ICON, "file:" + iconPath); //$NON-NLS-1$
+					}
 				}
 			}
 				break;
 			case (ITaglibRecord.JAR) : {
-				JarRecord record = (JarRecord) reference;
+				IJarRecord record = (IJarRecord) reference;
 				document = (CMDocumentImpl) buildCMDocumentFromJar(record.getLocation().toString());
 				if (document.getSmallIcon() != null) {
 					String iconPath = URIHelper.normalize(((TLDDocument) document).getSmallIcon(), record.getLocation().toString() + "!META-INF/", "/"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -645,7 +650,7 @@
 			}
 				break;
 			case (ITaglibRecord.URL) : {
-				URLRecord record = (URLRecord) reference;
+				IURLRecord record = (IURLRecord) reference;
 				InputStream urlContents = null;
 				URLConnection connection = null;
 				try {
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java
index 68e7e20..bb1b53f 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contentmodel/tld/TLDCMDocumentManager.java
@@ -249,7 +249,7 @@
 				includedFile = null;
 			}
 			if (includedFile != null) {
-				IPath root = TaglibIndex.getContextRoot(getCurrentBaseLocation());
+				IPath root = TaglibIndex.getContextRoot(TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation());
 				// strip any extraneous quotes and white space
 				includedFile = StringUtils.strip(includedFile).trim();
 				IPath fileLocation = null;
@@ -257,10 +257,10 @@
 					fileLocation = root.append(includedFile);
 				}
 				else {
-					fileLocation = new Path(URIHelper.normalize(includedFile, getCurrentBaseLocation().toString(), root.toString()));
+					fileLocation = new Path(URIHelper.normalize(includedFile, TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation().toString(), root.toString()));
 				}
 				// check for "loops"
-				if (!getIncludes().contains(fileLocation) && fileLocation != null && !fileLocation.equals(getCurrentBaseLocation())) {
+				if (!getIncludes().contains(fileLocation) && fileLocation != null && !fileLocation.equals(TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation())) {
 					/*
 					 * Prevent slow performance when editing scriptlet part of
 					 * the JSP by only processing includes if they've been
@@ -273,7 +273,7 @@
 						getIncludes().push(fileLocation);
 						if (getParser() != null) {
 							IncludeHelper includeHelper = new IncludeHelper(anchorStructuredDocumentRegion, getParser());
-							includeHelper.parse(fileLocation.toString());
+							includeHelper.parse(FileBuffers.normalizeLocation(fileLocation).toString());
 							List references = includeHelper.taglibReferences;
 							fTLDCMReferencesMap.put(fileLocation.toString(), references);
 						}
@@ -801,16 +801,11 @@
 	 */
 	IPath getCurrentBaseLocation() {
 		IPath baseLocation = null;
-		if (!getIncludes().isEmpty()) {
-			baseLocation = (IPath) getIncludes().peek();
-		}
-		else {
-			IPath path = TaglibController.getFileBuffer(this).getLocation();
-			if (path.toFile().exists())
-				baseLocation = path;
-			else
-				baseLocation = ResourcesPlugin.getWorkspace().getRoot().getFile(path).getLocation();
-		}
+		IPath path = TaglibController.getFileBuffer(this).getLocation();
+		if (path.toFile().exists())
+			baseLocation = path;
+		else
+			baseLocation = ResourcesPlugin.getWorkspace().getRoot().getFile(path).getLocation();
 		return baseLocation;
 	}
 
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java
index 2f780c0..c13c861 100644
--- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java
+++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibHyperlinkDetector.java
@@ -15,8 +15,8 @@
 import org.eclipse.jface.text.hyperlink.IHyperlink;
 import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
 import org.eclipse.jface.text.hyperlink.URLHyperlink;
+import org.eclipse.jst.jsp.core.internal.contentmodel.ITLDRecord;
 import org.eclipse.jst.jsp.core.internal.contentmodel.ITaglibRecord;
-import org.eclipse.jst.jsp.core.internal.contentmodel.TLDRecord;
 import org.eclipse.jst.jsp.core.internal.contentmodel.TaglibIndex;
 import org.eclipse.jst.jsp.core.internal.provisional.JSP11Namespace;
 import org.eclipse.jst.jsp.core.internal.provisional.text.IJSPPartitionTypes;
@@ -58,8 +58,8 @@
 								// handle taglibs
 								switch (reference.getRecordType()) {
 									case (ITaglibRecord.TLD) : {
-										TLDRecord record = (TLDRecord) reference;
-										String uriString = record.getLocation().toString();
+										ITLDRecord record = (ITLDRecord) reference;
+										String uriString = record.getPath().toString();
 										IRegion hyperlinkRegion = getHyperlinkRegion(taglibNode);
 										hyperlink = createHyperlink(uriString, hyperlinkRegion, doc, taglibNode);
 									}
@@ -141,7 +141,7 @@
 	 * file from uri.
 	 * 
 	 * @param fileString
-	 *            file system path
+	 *            file system or workspace-relative path
 	 * @return returns IFile if fileString exists in the workspace
 	 */
 	private IFile getFile(String fileString) {
@@ -153,6 +153,9 @@
 				if (files[i].exists())
 					file = files[i];
 		}
+		if(file == null) {
+			file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(fileString));
+		}
 
 		return file;
 	}
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibJarUriHyperlink.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibJarUriHyperlink.java
index aab8f40..1c8928d 100644
--- a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibJarUriHyperlink.java
+++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/hyperlink/TaglibJarUriHyperlink.java
@@ -2,9 +2,9 @@
 
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jst.jsp.core.internal.contentmodel.IJarRecord;
 import org.eclipse.jst.jsp.core.internal.contentmodel.ITaglibRecord;
-import org.eclipse.jst.jsp.core.internal.contentmodel.JarRecord;
-import org.eclipse.jst.jsp.core.internal.contentmodel.URLRecord;
+import org.eclipse.jst.jsp.core.internal.contentmodel.IURLRecord;
 
 /**
  * Hyperlink for taglib files in jars or specified by urls.
@@ -23,12 +23,12 @@
 		if (fHyperlink == null && fTaglibRecord != null) {
 			switch (fTaglibRecord.getRecordType()) {
 				case (ITaglibRecord.JAR) : {
-					JarRecord record = (JarRecord) fTaglibRecord;
+					IJarRecord record = (IJarRecord) fTaglibRecord;
 					fHyperlink = new TaglibJarHyperlink(fRegion, record.getLocation());
 				}
 					break;
 				case (ITaglibRecord.URL) : {
-					URLRecord record = (URLRecord) fTaglibRecord;
+					IURLRecord record = (IURLRecord) fTaglibRecord;
 					fHyperlink = new URLFileHyperlink(fRegion, record.getURL());
 				}
 			}