Initial commit of internet cache plugin.
diff --git a/plugins/org.eclipse.wst.internet.cache/.classpath b/plugins/org.eclipse.wst.internet.cache/.classpath
new file mode 100644
index 0000000..065ac06
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.wst.internet.cache/.cvsignore b/plugins/org.eclipse.wst.internet.cache/.cvsignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/plugins/org.eclipse.wst.internet.cache/.project b/plugins/org.eclipse.wst.internet.cache/.project
new file mode 100644
index 0000000..d7188f0
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.wst.internet.cache</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.wst.internet.cache/META-INF/MANIFEST.MF b/plugins/org.eclipse.wst.internet.cache/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6a88219
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/META-INF/MANIFEST.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %_PLUGIN_NAME
+Bundle-SymbolicName: org.eclipse.wst.internet.cache; singleton:=true
+Bundle-Version: 1.0.0
+Bundle-ClassPath: cache.jar
+Bundle-Activator: org.eclipse.wst.internet.cache.internal.CachePlugin
+Bundle-Vendor: %_PLUGIN_PROVIDER
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.wst.common.uriresolver,
+ org.eclipse.core.resources,
+ org.eclipse.wst.xml.uriresolver
+Eclipse-AutoStart: true
+Export-Package: org.eclipse.wst.internet.cache.internal;x-friends:="org.eclipse.wst.internal.cache.tests"
diff --git a/plugins/org.eclipse.wst.internet.cache/build.properties b/plugins/org.eclipse.wst.internet.cache/build.properties
new file mode 100644
index 0000000..8fbaaaa
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/build.properties
@@ -0,0 +1,5 @@
+source.cache.jar = src/
+output.cache.jar = bin/
+bin.includes = plugin.xml,\
+               META-INF/,\
+               cache.jar
diff --git a/plugins/org.eclipse.wst.internet.cache/exsd/cacheresource.exsd b/plugins/org.eclipse.wst.internet.cache/exsd/cacheresource.exsd
new file mode 100644
index 0000000..d42a334
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/exsd/cacheresource.exsd
@@ -0,0 +1,101 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.wst.internet.cache">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="org.eclipse.wst.internet.cache" id="cacheresource" name="Cache a resource"/>
+      </appInfo>
+      <documentation>
+         [Enter description of this extension point.]
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <complexType>
+         <sequence>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appInfo>
+                  <meta.attribute translatable="true"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="cacheresource">
+      <complexType>
+         <attribute name="uri" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="implementation"/>
+      </appInfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/plugins/org.eclipse.wst.internet.cache/plugin.properties b/plugins/org.eclipse.wst.internet.cache/plugin.properties
new file mode 100644
index 0000000..88ebd84
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/plugin.properties
@@ -0,0 +1,15 @@
+###############################################################################
+# 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
+###############################################################################
+
+_PLUGIN_PROVIDER                       = Eclipse
+_PLUGIN_NAME                           = Cache URI Resolver Plug-in
+
+_UI_CACHE_PREFERENCE_PAGE_TITLE        = Cache
\ No newline at end of file
diff --git a/plugins/org.eclipse.wst.internet.cache/plugin.xml b/plugins/org.eclipse.wst.internet.cache/plugin.xml
new file mode 100644
index 0000000..6d26909
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/plugin.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+
+   <extension-point name="Cache a resource" id="cacheresource" schema="exsd/cacheresource.exsd"/>
+
+   <extension
+         point="org.eclipse.ui.preferencePages">
+      <page
+            name="%_UI_CACHE_PREFERENCE_PAGE_TITLE"
+            class="org.eclipse.wst.internet.cache.internal.preferences.CachePreferencePage"
+            id="org.eclipse.wst.internet.cache.internal.preferences.CachePreferencePage"
+            category = "org.eclipse.internet">
+      </page>
+   </extension>
+   <extension
+         point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.eclipse.wst.internet.cache.internal.preferences.PreferenceInitializer">
+      </initializer>
+   </extension>
+   
+   <extension point="org.eclipse.wst.common.uriresolver.resolverExtensions">
+      <resolverExtension
+            stage="postnormalization"
+            class="org.eclipse.wst.internet.cache.internal.CacheURIResolverExtension">
+      </resolverExtension>
+   </extension>
+   
+   <extension point="org.eclipse.wst.internet.cache.cacheresource">
+     <cacheresource uri="http://schemas.xmlsoap.org/wsdl/"/>
+     <cacheresource uri="http://schemas.xmlsoap.org/wsdl/soap/"/>
+     <cacheresource uri="http://schemas.xmlsoap.org/wsdl/mime/"/>
+     <cacheresource uri="http://schemas.xmlsoap.org/wsdl/http/"/>
+   </extension> 
+</plugin>
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/Cache.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/Cache.java
new file mode 100644
index 0000000..fbb00b8
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/Cache.java
@@ -0,0 +1,522 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Random;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * The cache holds references to remote resources. The cache can store resources,
+ * retrieve resources, and delete resources.
+ *
+ */
+public class Cache 
+{
+  /**
+   * String instances.
+   */
+  private static final String URI = "uri";
+  private static final String LOCATION ="location";
+  private static final String ENTRY = "entry";
+  private static final String CACHE = "cache";
+  private static final String LAST_MODIFIED = "lastModified";
+  private static final String EXPIRATION_TIME = "expirationTime";
+  private static final String FILE_PROTOCOL = "file:///";
+  private static final String CACHE_FILE = "cache.xml";
+  private static final String CACHE_EXTENSION = ".cache";
+  private static final String TEMP = "temp";
+  private static final String CACHE_PREFIX = "wtpcache";
+  private static final String CACHE_SUFFIX = null;
+  /**
+   * The default timeout for a cache entry is 1 day.
+   */
+  private static final long TIMEOUT = 86400000;
+	
+  /**
+   * The one and only instance of the cache.
+   */
+  private static Cache cacheInstance = null;
+  
+  /**
+   * The cache is stored in a hashtable.
+   */
+  private Hashtable cache;
+  
+  /**
+   * A set of uncached resources. The cache was not able to cache resources
+   * in this list. This list allows quickly skipping over these resources in
+   * future requests. 
+   */
+  private Set uncached;
+  
+  /**
+   * The location of the cache
+   */
+  private File cacheLocation = null;
+  
+  /**
+   * Private constructor.
+   */
+  protected Cache(IPath cacheLocation)
+  {
+	  this.cacheLocation = cacheLocation.toFile();//Platform.getPluginStateLocation(CachePlugin.getDefault()).toFile();
+    cache = new Hashtable();
+    uncached = new HashSet();
+  }
+  
+  /**
+   * Get the one and only instance of the cache.
+   * 
+   * @return The one and only instance of the cache.
+   */
+  public static Cache getInstance()
+  {
+//	  if(cacheInstance == null)
+//	  {
+//		  cacheInstance = new Cache(cacheLocation);
+//		  cacheInstance.open(cacheLocation);
+//	  }
+	  return cacheInstance;
+  }
+  
+  /**
+   * Return the local resource for the specified uri. If there is no resource
+   * the cache will attempt to download and cache the resource before returning.
+   * If a remote resource cannot be cached this method will return null.
+   * 
+   * @param uri The URI for which a resource is requested.
+   * @return The local resource for the specified URI or null if a remote resource cannot be cached.
+   */
+  public String getResource(String uri)
+  {
+	  if(uri == null) return null;
+	  CacheEntry result = (CacheEntry)cache.get(uri);
+	  
+	  // If no result is in the cache and the URI is of an allowed type
+	  // retrieve it and store it in the cache.
+	  if(result == null)
+	  {
+      
+      if(!uncached.contains(result))
+		  {
+        result = cacheResource(uri); 
+      }
+	  }
+	  // Retreive a fresh copy of the result if it has timed out.
+	  else if(result.hasExpired())
+	  {
+		result = refreshCacheEntry(result);
+	  }
+	  if(result == null || result.getLocalFile() == null)
+	  {
+		return null;
+	  }
+	  return FILE_PROTOCOL + cacheLocation.toString() + "/" + result.getLocalFile();
+  }
+  
+  /**
+   * Get the list of uncached resources.
+   * 
+   * @return The list of uncached resources.
+   */
+  protected String[] getUncachedURIs()
+  {
+    return (String[])uncached.toArray(new String[uncached.size()]);
+  }
+  
+  /**
+   * Clear the list of uncached resources.
+   */
+  protected void clearUncachedURIs()
+  {
+    uncached.clear();
+  }
+  
+  /**
+   * Add an uncached resource to the list.
+   */
+  protected void addUncachedURI(String uri)
+  {
+    uncached.add(uri);
+  }
+  
+  /**
+   * Cache the specified resource. This method creates a local version of the
+   * remote resource and adds the resource reference to the cache. If the resource
+   * cannot be accessed it is not added and null is returned.
+   * 
+   * @param uri The remote URI to cache.
+   * @return A new CacheEntry representing the cached resource or null if the remote
+   *         resource could not be retrieved.
+   */
+  protected CacheEntry cacheResource(String uri)
+  {
+	  CacheEntry cacheEntry = null;
+	  URLConnection conn = null;
+	  InputStream is = null;
+	  OutputStream os = null;
+	  try
+	  {
+		  URL url = new URL(uri);
+		  conn = url.openConnection();
+		  conn.connect();
+		  // Determine if this resource can be cached.
+		  if(conn.getUseCaches())
+		  {
+		    is = conn.getInputStream();//url.openStream();
+		  
+		    Random rand = new Random();
+			String fileName = rand.nextInt() + CACHE_EXTENSION;
+		    File file = new File(cacheLocation, fileName);
+		    // If the file already exists we need to change the file name.
+		    while(!file.createNewFile())
+		    {
+			  fileName = rand.nextInt() + CACHE_EXTENSION;
+			  file = new File(cacheLocation,fileName);
+		    }
+		    os = new FileOutputStream(file);
+		    byte[] bytes = new byte[1024];
+		    int bytelength;
+		    while((bytelength = is.read(bytes)) != -1)
+		    {
+			  os.write(bytes, 0, bytelength);
+		    }
+			long lastModified = conn.getLastModified();
+		    long expiration = conn.getExpiration();
+			if(expiration == 0)
+			{
+			  expiration = System.currentTimeMillis() + TIMEOUT;
+			}
+		    cacheEntry = new CacheEntry(uri, fileName, lastModified, expiration);
+		    cache.put(uri,cacheEntry);
+		  }
+
+	  }
+	  catch(Throwable t)
+	  {
+		  // Put the entry in the uncached list so the resolution work will not be performed again.
+      // TODO: Add in a timeout for the non-located uris.
+      uncached.add(uri);
+	  }
+	  finally
+	  {
+		  if(is != null)
+		  {
+			  try
+			  {
+			    is.close();
+			  }
+			  catch(IOException e)
+			  {
+			    // Do nothing if the stream cannot be closed.
+			  }
+		  }
+		  if(os != null)
+		  {
+			  try
+			  {
+			    os.close();
+			  }
+			  catch(IOException e)
+			  {
+				// Do nothing if the stream cannot be closed. 
+			  }
+		  }
+	  }
+	  return cacheEntry;
+  }
+  
+  /**
+   * Refresh the cache entry if necessary. The cache entry will be refreshed
+   * if the remote resource is accessible and the last modified time of the
+   * remote resource is greater than the last modified time of the cached
+   * resource.
+   * 
+   * @param cacheEntry The cache entry to refresh.
+   * @return The refreshed cache entry.
+   */
+  protected CacheEntry refreshCacheEntry(CacheEntry cacheEntry)
+  {
+	  URLConnection conn = null;
+	  InputStream is = null;
+	  OutputStream os = null;
+	  try
+	  {
+		  URL url = new URL(cacheEntry.getURI());
+		  conn = url.openConnection();
+		  conn.connect();
+		  
+		  long lastModified = conn.getLastModified();
+	      if(lastModified > cacheEntry.getLastModified())
+		  {
+			long expiration = conn.getExpiration();
+		    if(expiration == 0)
+			{
+			  expiration = System.currentTimeMillis() + TIMEOUT;
+			}
+			
+		    is = conn.getInputStream();
+			
+			String localFile = cacheEntry.getLocalFile();
+  
+		    File tempFile = File.createTempFile(CACHE_PREFIX, CACHE_SUFFIX);
+			tempFile.deleteOnExit();
+
+		    os = new FileOutputStream(tempFile);
+		    byte[] bytes = new byte[1024];
+		    int bytelength;
+		    while((bytelength = is.read(bytes)) != -1)
+		    {
+			  os.write(bytes, 0, bytelength);
+		    }
+			is.close();
+			os.close();
+			deleteFile(cacheEntry.getURI());
+			File f = new File(cacheLocation, localFile);
+			tempFile.renameTo(f);
+			cacheEntry.setExpiration(expiration);
+			cacheEntry.setLastModified(lastModified);
+		  }
+		  // The cache entry hasn't changed. Just update the expiration time.
+	      else
+		  {
+			long expiration = conn.getExpiration();
+			if(expiration == 0)
+			{
+			  expiration = System.currentTimeMillis() + TIMEOUT;
+			}
+			cacheEntry.setExpiration(expiration);
+		  }
+
+	  }
+	  catch(Exception e)
+	  {
+		  System.out.println(e);
+	  }
+	  finally
+	  {
+		  if(is != null)
+		  {
+			  try
+			  {
+			    is.close();
+			  }
+			  catch(IOException e)
+			  {
+			    // Do nothing if the stream cannot be closed.
+			  }
+		  }
+		  if(os != null)
+		  {
+			  try
+			  {
+			    os.close();
+			  }
+			  catch(IOException e)
+			  {
+				// Do nothing if the stream cannot be closed. 
+			  }
+		  }
+	  }
+	  return cacheEntry;
+  }
+  
+  /**
+   * Get an array of the cached URIs.
+   * 
+   * @return An array of the cached URIs.
+   */
+  public String[] getCachedURIs()
+  {
+	Set keyset = cache.keySet();
+	return (String[])keyset.toArray(new String[keyset.size()]);
+  }
+  
+  /**
+   * Close the cache. Closing the cache involves serializing the data to an XML file
+   * in the plugin state location.
+   */
+  protected void close()
+  {
+	  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      try {
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document cachedoc = builder.newDocument();
+		Element rootelem = cachedoc.createElement(CACHE);
+		cachedoc.appendChild(rootelem);
+		
+	  Enumeration uris = cache.keys();
+	  while(uris.hasMoreElements())
+	  {
+		  String key = (String)uris.nextElement();
+		  CacheEntry cacheEntry = (CacheEntry)cache.get(key);
+		  if(cacheEntry != null)
+		  {
+			  Element entry = cachedoc.createElement(ENTRY);
+			  entry.setAttribute(URI, key);
+			  entry.setAttribute(LOCATION, cacheEntry.getLocalFile());
+			  entry.setAttribute(EXPIRATION_TIME, String.valueOf(cacheEntry.getExpirationTime()));
+			  entry.setAttribute(LAST_MODIFIED, String.valueOf(cacheEntry.getLastModified()));
+			  rootelem.appendChild(entry);
+		  }
+	  }
+	  
+	  // Write the cache entry.
+	  TransformerFactory tFactory  = TransformerFactory.newInstance();
+      Transformer transformer = tFactory.newTransformer();
+      Source input = new DOMSource(cachedoc);
+	  IPath stateLocation = Platform.getPluginStateLocation(CachePlugin.getDefault());
+      Result output = new StreamResult(stateLocation.toString() + "/" + CACHE_FILE);
+      transformer.transform(input, output);
+
+      }catch(Exception e)
+	  {
+		  System.out.println("Unable to store internet cache.");
+	  }
+	  cacheInstance = null;
+  }
+  
+  /**
+   * Open the cache. Opening the cache involves parsing the cache XML file in
+   * the plugin state location if it can be read.
+   */
+  protected static void open(IPath cacheLocation)
+  {
+    cacheInstance = new Cache(cacheLocation);
+	  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      try {
+		  
+		IPath stateLocation = cacheLocation;
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document cachedoc = builder.parse(stateLocation.toString() + "/" + CACHE_FILE);
+		Element rootelem = cachedoc.getDocumentElement();
+		NodeList entries = rootelem.getChildNodes();
+		int numEntries = entries.getLength();
+		for(int i = 0; i < numEntries; i++)
+		{
+			Node entry = entries.item(i);
+			if(entry instanceof Element)
+			{
+				Element e = (Element)entry;
+				if(e.getNodeName().equals(ENTRY))
+				{
+					String uri = e.getAttribute(URI);
+					String location = e.getAttribute(LOCATION);
+					String lm = e.getAttribute(LAST_MODIFIED);
+					String et = e.getAttribute(EXPIRATION_TIME);
+					long lastModified = -1;
+					long expirationTime = -1;
+					try
+					{
+						lastModified = Long.parseLong(lm);
+					}
+					catch(NumberFormatException nfe)
+					{
+					}
+					try
+					{
+						expirationTime = Long.parseLong(et);
+					}
+					catch(NumberFormatException nfe)
+					{
+					}
+					if(uri != null && location != null)
+					{
+					  cacheInstance.cache.put(uri, new CacheEntry(uri, location, lastModified, expirationTime));
+					}
+				}
+			}
+		}
+      }
+	  catch(FileNotFoundException e)
+	  {
+		// If the file doesn't exist in the correct location there is nothing to load. Do nothing.
+	  }
+	  catch(Exception e)
+	  {
+		  System.out.println("Unable to load cache.");
+	  }
+  }
+  
+  /**
+   * Clear all of the entries from the cache. This method also deletes the cache files.
+   */
+  public void clear()
+  {
+	Enumeration keys = cache.keys();
+	while(keys.hasMoreElements())
+	{
+	  String key = (String)keys.nextElement();
+	  
+	  deleteFile(key);
+	}
+	cache.clear();
+  }
+  
+  /**
+   * Delete the cache entry specified by the given URI.
+   * @param uri The URI entry to remove from the catalog.
+   */
+  public void deleteEntry(String uri)
+  {
+	  if(uri == null) return;
+	  
+	  deleteFile(uri);
+	  cache.remove(uri);
+  }
+  
+  /**
+   * Delete the file specified by the URI.
+   * 
+   * @param uri The URI of the file to delete.
+   */
+  protected void deleteFile(String uri)
+  {
+	  CacheEntry cacheEntry = (CacheEntry)cache.get(uri);
+	  if(cacheEntry != null)
+	  {
+		String location = cacheLocation.toString() + "/" + cacheEntry.getLocalFile();
+	    File file = new File(location);
+	    if(!file.delete())
+	    {
+	      System.out.println("Unable to delete file " + location + " from cache.");
+	    } 
+	  }
+  }
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheEntry.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheEntry.java
new file mode 100644
index 0000000..817ec06
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheEntry.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal;
+
+/**
+ * A cache entry contains a URI, a local file, and a timeout.
+ */
+public class CacheEntry 
+{
+  private String uri;
+  private String localFile;
+  private long lastModified;
+  private long expirationTime;
+  
+  /**
+   * Create a new cache entry.
+   * 
+   * @param uri The remote URI of the cache entry.
+   * @param localFile The local file that contains the cached entry.
+   * @param lastModifie The time this resource was last modified.
+   * @param expirationTime The time in miliseconds that this cache entry will
+   *                       expire.
+   */
+  public CacheEntry(String uri, String localFile, long lastModified, long expirationTime)
+  {
+	this.uri = uri;
+	this.localFile = localFile;
+	this.lastModified = lastModified;
+	this.expirationTime = expirationTime;
+  }
+  
+  /**
+   * The cache entry is expired if its expiration time is less then the
+   * current system time and not equal to -1.
+   * 
+   * @return True if this cached entry has expired, false otherwise.
+   */
+  public boolean hasExpired()
+  {
+	 if(expirationTime != -1 && System.currentTimeMillis() > expirationTime)
+	 {
+	   return true;
+	 }
+	 return false;
+  }
+  
+  /**
+   * Set the time in miliseconds that this cache entry will expire.
+   * 
+   * @param timeout The time in miliseconds that this cache entry will expire.
+   *                -1 indicates that this entry will not expire.
+   */
+  public void setExpiration(long expirationTime)
+  {
+	this.expirationTime = expirationTime;
+  }
+  
+  /**
+   * Get the time at which this cache entry will expire.
+   * 
+   * @return The time at which this cache entry will expire.
+   */
+  public long getExpirationTime()
+  {
+	return expirationTime;
+  }
+  
+  /**
+   * Get the remote URI for this cache entry.
+   * 
+   * @return The remote URI for this cache entry.
+   */
+  public String getURI()
+  {
+	return uri;
+  }
+  
+  /**
+   * Get the local file for this cache entry.
+   * 
+   * @return The local file for this cache entry.
+   */
+  public String getLocalFile()
+  {
+	return localFile;
+  }
+  
+  /**
+   * Get the last time this cache entry was modified.
+   * 
+   * @return The last time this cache entry was modified.
+   */
+  public long getLastModified()
+  {
+	return lastModified;
+  }
+  
+  /**
+   * Set the last time this cache entry was modified.
+   */
+  public void setLastModified(long lastModified)
+  {
+	this.lastModified = lastModified;
+  }
+}
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheJob.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheJob.java
new file mode 100644
index 0000000..af553ae
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheJob.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * A cache job runs once an hour to cache any prespecified resources which
+ * should be cached and any resources for which an attempt was previously 
+ * made to cache them but they were unable to be cached.
+ */
+public class CacheJob extends Job
+{
+  private static final String _UI_CACHE_MONITOR_NAME = "_UI_CACHE_MONITOR_NAME";
+  private static final String _UI_CACHE_MONITOR_CACHING = "_UI_CACHE_MONITOR_CACHING";
+  private String[] specifiedURIsToCache;
+  private static final long SCHEDULE_TIME = 3600000;
+
+  /**
+   * Constructor.
+   */
+  public CacheJob()
+  {
+    super(CachePlugin.getResourceString(_UI_CACHE_MONITOR_NAME));
+    specifiedURIsToCache = ToCacheRegistryReader.getInstance().getURIsToCache();
+  }
+
+  /**
+   * @see org.eclipse.core.internal.jobs.InternalJob#run(org.eclipse.core.runtime.IProgressMonitor)
+   */
+  protected IStatus run(IProgressMonitor monitor)
+  {
+    Cache cache = Cache.getInstance();
+    String[] uncachedURIs = cache.getUncachedURIs();
+    int numUncachedURIs = uncachedURIs.length;
+    // Special case for the first time the job is run which will attemp to 
+    // cache specified resources.
+    if(specifiedURIsToCache != null)
+    {
+      int numSpecifiedURIs = specifiedURIsToCache.length;
+      String[] temp = new String[numUncachedURIs + numSpecifiedURIs];
+      System.arraycopy(specifiedURIsToCache, 0, temp, 0, numSpecifiedURIs);
+      System.arraycopy(uncachedURIs, 0, temp, numSpecifiedURIs, numUncachedURIs);
+      uncachedURIs = temp;
+      numUncachedURIs = uncachedURIs.length;
+      specifiedURIsToCache = null;
+    }
+
+    cache.clearUncachedURIs();
+    monitor.beginTask(CachePlugin.getResourceString(_UI_CACHE_MONITOR_NAME), numUncachedURIs);
+    try
+    {
+      for(int i = 0; i < numUncachedURIs; i++)
+      {
+        if (monitor.isCanceled())
+        {
+          for(int j = i; j < numUncachedURIs; j++)
+          {
+            cache.addUncachedURI(uncachedURIs[j]);
+          }
+          return Status.CANCEL_STATUS;
+        }
+        String uri = uncachedURIs[i];
+        monitor.subTask(CachePlugin.getResourceString(_UI_CACHE_MONITOR_CACHING, uri));
+        cache.getResource(uri);
+        monitor.worked(1);
+        monitor.subTask("");
+      }
+      monitor.done();
+      return Status.OK_STATUS;
+    } 
+    finally
+    {
+      schedule(SCHEDULE_TIME); // schedule the next time the job should run
+    }
+  }
+
+}
+
+
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CachePlugin.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CachePlugin.java
new file mode 100644
index 0000000..fd366b5
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CachePlugin.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.wst.internet.cache.internal.preferences.PreferenceConstants;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The main plugin class to be used in the desktop.
+ */
+public class CachePlugin extends AbstractUIPlugin {
+  
+	//The shared instance.
+	private static CachePlugin plugin;
+	//Resource bundle.
+	private ResourceBundle resourceBundle;
+  
+  private CacheJob job;
+	
+	/**
+	 * The constructor.
+	 */
+	public CachePlugin() {
+		super();
+		plugin = this;
+	}
+
+	/**
+	 * This method is called upon plug-in activation
+	 */
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+    ToCacheRegistryReader.getInstance().readRegistry();
+    Cache.open(Platform.getPluginStateLocation(this));
+    if(getPluginPreferences().contains(PreferenceConstants.CACHE_ENABLED))
+    {
+      setCacheEnabled(getPluginPreferences().getBoolean(PreferenceConstants.CACHE_ENABLED));
+    }
+    else
+    {
+      setCacheEnabled(true);
+    }
+	}
+
+	/**
+	 * This method is called when the plug-in is stopped
+	 */
+	public void stop(BundleContext context) throws Exception {
+		Cache.getInstance().close();
+    stopJob();
+		super.stop(context);
+		plugin = null;
+		resourceBundle = null;
+	}
+
+	/**
+	 * Returns the shared instance.
+	 */
+	public static CachePlugin getDefault() {
+		return plugin;
+	}
+
+	/**
+	 * Returns the string from the plugin's resource bundle,
+	 * or 'key' if not found.
+	 */
+	public static String getResourceString(String key) {
+		ResourceBundle bundle = ResourceBundle.getBundle("org.eclipse.wst.internet.cache.internal.CachePluginResources");
+		try {
+			return (bundle != null) ? bundle.getString(key) : key;
+		} catch (MissingResourceException e) {
+			return key;
+		}
+	}
+  
+  /**
+   * Returns the string from the plugin's resource bundle using the specified object,
+   * or 'key' if not found.
+   */
+  public static String getResourceString(String key, Object s1)
+  {
+    return MessageFormat.format(getResourceString(key), new Object[] { s1 });
+  }
+
+	/**
+	 * Returns the plugin's resource bundle,
+	 */
+	public ResourceBundle getResourceBundle() {
+		try {
+			if (resourceBundle == null)
+				resourceBundle = ResourceBundle.getBundle("plugin");
+		} catch (MissingResourceException x) {
+			resourceBundle = null;
+		}
+		return resourceBundle;
+	}
+
+	/**
+	 * Returns an image descriptor for the image file at the given
+	 * plug-in relative path.
+	 *
+	 * @param path the path
+	 * @return the image descriptor
+	 */
+	public static ImageDescriptor getImageDescriptor(String path) {
+		return AbstractUIPlugin.imageDescriptorFromPlugin("org.eclipse.wst.internet.cache", path);
+	}
+  
+  public void setCacheEnabled(boolean enabled)
+  {
+    getPluginPreferences().setValue(PreferenceConstants.CACHE_ENABLED, enabled);
+    if(enabled)
+    {
+      startJob();
+    }
+    else
+    {
+      stopJob();
+    }
+  }
+  
+  public boolean isCacheEnabled()
+  {
+    if(getPluginPreferences().contains(PreferenceConstants.CACHE_ENABLED))
+      return getPluginPreferences().getBoolean(PreferenceConstants.CACHE_ENABLED);
+    return true;
+  }
+  
+  private void startJob()
+  {
+    if(job == null)
+    {
+      job = new CacheJob();
+      job.setPriority(CacheJob.DECORATE);
+      job.schedule(); // start as soon as possible
+    }
+  }
+  
+  private void stopJob()
+  {
+    if(job != null)
+    {
+      job.cancel();
+    }
+    job = null;
+  }
+}
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CachePluginResources.properties b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CachePluginResources.properties
new file mode 100644
index 0000000..9fd0a38
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CachePluginResources.properties
@@ -0,0 +1,24 @@
+###############################################################################
+# 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
+###############################################################################
+
+# Cache preference page strings.
+_UI_CONFIRM_CLEAR_CACHE_DIALOG_TITLE          = Clear Cache?
+_UI_CONFIRM_CLEAR_CACHE_DIALOG_MESSAGE        = Delete all cache entries?
+_UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_TITLE   = Delete Entry?
+_UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_MESSAGE = Delete all selected cache entries?
+_UI_BUTTON_CLEAR_CACHE                        = Clear Cache
+_UI_BUTTON_DELETE_ENTRY                       = Delete Entry
+_UI_PREF_CACHE_ENTRIES_TITLE                  = Cache Entries
+_UI_PREF_CACHE_CACHE_OPTION                   = Disable Caching
+
+# Cache monitor strings.
+_UI_CACHE_MONITOR_NAME                        = Caching Remote Resources
+_UI_CACHE_MONITOR_CACHING                     = Caching {0}
\ No newline at end of file
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheURIResolverExtension.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheURIResolverExtension.java
new file mode 100644
index 0000000..7113855
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/CacheURIResolverExtension.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.wst.common.uriresolver.URIResolverExtension;
+import org.eclipse.wst.xml.uriresolver.util.URIHelper;
+
+/**
+ * A cache URI resolver. This resolver will cache remote resources and return
+ * the local copy if they can be cached. If a resource cannot be cached the
+ * resource returns null.
+ */
+public class CacheURIResolverExtension implements URIResolverExtension 
+{
+	/**
+	 * @see org.eclipse.wst.common.uriresolver.URIResolverExtension#resolve(org.eclipse.core.resources.IProject, java.lang.String, java.lang.String, java.lang.String)
+	 */
+	public String resolve(IProject project, String baseLocation, String publicId, String systemId)
+	{ 
+    if(CachePlugin.getDefault().isCacheEnabled())
+    {
+		  String resource = null;
+		  if(systemId != null)
+		  {
+		    resource = URIHelper.normalize(systemId, baseLocation, null);
+		  } 
+		
+		  if(resource != null && (resource.startsWith("http:") || resource.startsWith("ftp:")))
+		  {
+		    return Cache.getInstance().getResource(resource);
+		  }
+    }
+		return null;
+	  }
+}
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/ToCacheRegistryReader.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/ToCacheRegistryReader.java
new file mode 100644
index 0000000..9d93a5b
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/ToCacheRegistryReader.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * The ToCacheRegistryReaders reads Eclipse extensions which specify
+ * resources to cache. An extension point looks like the following.
+ * 
+ *  <extension point="org.eclipse.wst.internet.cache.cacheresource">
+ *    <cacheresource uri="URI_TO_CACHE"/>
+ *  </extension> 
+ *
+ */
+public class ToCacheRegistryReader
+{
+  protected static final String PLUGIN_ID = "org.eclipse.wst.internet.cache";
+  protected static final String EXTENSION_POINT_ID = "cacheresource";
+  protected static final String ATT_URI = "uri";
+ 
+  private static ToCacheRegistryReader registryReader = null;
+  
+  private Set resourcesToCache = new HashSet();
+
+  /**
+   * Get the one and only instance of this registry reader.
+   * 
+   * @return The one and only instance of this registry reader.
+   */
+  public static ToCacheRegistryReader getInstance()
+  {
+    if(registryReader == null)
+    {
+      registryReader = new ToCacheRegistryReader();
+    }
+    return registryReader;
+  }
+  /**
+   * Read from plugin registry and handle the configuration elements that match
+   * the spedified elements.
+   */
+  public void readRegistry()
+  {
+    IExtensionRegistry pluginRegistry = Platform.getExtensionRegistry();
+    IExtensionPoint point = pluginRegistry.getExtensionPoint(PLUGIN_ID, EXTENSION_POINT_ID);
+    if (point != null)
+    {
+      IConfigurationElement[] elements = point.getConfigurationElements();
+      for (int i = 0; i < elements.length; i++)
+      {
+        String uri = readElement(elements[i]);
+        if(uri != null)
+        {
+          resourcesToCache.add(uri);
+        }
+      }
+    }
+  }
+
+  /**
+   * Parse and deal with the extension points.
+   * 
+   * @param element The extension point element.
+   */
+  protected String readElement(IConfigurationElement element)
+  {
+    if(element.getName().equals(EXTENSION_POINT_ID))
+    {
+      return element.getAttribute(ATT_URI);
+    }
+    return null;
+  }
+  
+  /**
+   * Get the list of URIs that have been specified for caching.
+   * 
+   * @return The list of URIs that have been specified for caching.
+   */
+  public String[] getURIsToCache()
+  {
+    return (String[])resourcesToCache.toArray(new String[resourcesToCache.size()]);
+  }
+}
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/CachePreferencePage.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/CachePreferencePage.java
new file mode 100644
index 0000000..34382b2
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/CachePreferencePage.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal.preferences;
+
+import java.util.Arrays;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.wst.internet.cache.internal.Cache;
+import org.eclipse.wst.internet.cache.internal.CachePlugin;
+
+/**
+ * This class represents a preference page that is contributed to the 
+ * Preferences dialog. This page contains options for the cache. The cache
+ * can be disabled, the list of entries in the cache can be viewed, and 
+ * individual entries or the entire cache can be deleted.
+ */
+
+public class CachePreferencePage extends PreferencePage implements IWorkbenchPreferencePage 
+{
+	private static final String _UI_CONFIRM_CLEAR_CACHE_DIALOG_TITLE = "_UI_CONFIRM_CLEAR_CACHE_DIALOG_TITLE";
+	private static final String _UI_CONFIRM_CLEAR_CACHE_DIALOG_MESSAGE = "_UI_CONFIRM_CLEAR_CACHE_DIALOG_MESSAGE";
+	private static final String _UI_BUTTON_CLEAR_CACHE = "_UI_BUTTON_CLEAR_CACHE";
+	private static final String _UI_BUTTON_DELETE_ENTRY = "_UI_BUTTON_DELETE_ENTRY";
+	private static final String _UI_PREF_CACHE_ENTRIES_TITLE = "_UI_PREF_CACHE_ENTRIES_TITLE";
+  private static final String _UI_PREF_CACHE_OPTIONS_TITLE = "_UI_PREF_CACHE_OPTIONS_TITLE";
+  private static final String _UI_PREF_CACHE_CACHE_OPTION = "_UI_PREF_CACHE_CACHE_OPTION";
+  private static final String _UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_TITLE = "_UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_TITLE";
+  private static final String _UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_MESSAGE = "_UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_MESSAGE";
+	
+	protected Button clearButton;
+	protected Button deleteButton;
+  protected Button enabledButton;
+	protected List entries;
+  protected Composite composite = null;
+  protected Group entriesGroup;
+
+	/**
+	 * @see org.eclipse.jface.dialogs.IDialogPage#dispose()
+	 */
+	public void dispose()
+  {
+    if(composite != null)
+    {
+      composite.dispose();
+    }
+    super.dispose();
+  }
+
+  /**
+   * Constructor.
+   */
+  public CachePreferencePage() 
+	{
+		setPreferenceStore(CachePlugin.getDefault().getPreferenceStore());
+	}
+	
+	/**
+	 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+	 */
+	public void init(IWorkbench workbench) 
+	{
+	}
+
+	/**
+	 * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
+	 */
+	protected Control createContents(Composite parent) 
+	{
+		noDefaultAndApplyButton();
+		composite = new Composite(parent, SWT.NULL);
+		composite.setLayout(new GridLayout());
+		GridData gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
+		gd.grabExcessHorizontalSpace = true;
+		gd.grabExcessVerticalSpace = true;
+	    composite.setLayoutData(gd);
+      try
+      {
+		GridLayout gridLayout = new GridLayout();
+    
+    // Created the disable cache option.
+    enabledButton = new Button(composite, SWT.CHECK | SWT.LEFT);
+    enabledButton.setText(CachePlugin.getResourceString(_UI_PREF_CACHE_CACHE_OPTION));
+    enabledButton.setSelection(!CachePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.CACHE_ENABLED));
+    enabledButton.addSelectionListener(new SelectionListener(){
+
+      public void widgetDefaultSelected(SelectionEvent e)
+      {
+        widgetSelected(e);
+        
+      }
+
+      public void widgetSelected(SelectionEvent e)
+      {
+        boolean disabled = enabledButton.getSelection();
+        CachePlugin.getDefault().setCacheEnabled(!disabled);
+        setPreferenceWidgets();
+      }
+      
+      
+      
+    });
+		
+		// Create the entities group.
+		entriesGroup = new Group(composite, SWT.NONE);
+	  entriesGroup.setText(CachePlugin.getResourceString(_UI_PREF_CACHE_ENTRIES_TITLE));
+	  gridLayout = new GridLayout();
+	  entriesGroup.setLayout(gridLayout);
+	  GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.grabExcessVerticalSpace = true;
+	  entriesGroup.setLayoutData(gridData);
+    
+		entries = new List(entriesGroup, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
+		String[] cacheEntries = Cache.getInstance().getCachedURIs();
+		Arrays.sort(cacheEntries);
+		entries.setItems(cacheEntries);
+		gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.grabExcessVerticalSpace = true;
+	    entries.setLayoutData(gridData);
+		entries.addSelectionListener(new SelectionAdapter() {
+	          public void widgetSelected(SelectionEvent event) {
+              setPreferenceWidgets();
+	          }
+	       });
+		
+		Composite buttonComposite = new Composite(composite, SWT.NULL);
+		gridLayout = new GridLayout();
+		gridLayout.numColumns = 2;
+		buttonComposite.setLayout(gridLayout);
+		gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL |GridData.HORIZONTAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_END);
+	    composite.setLayoutData(gridData);
+		// Create the Delete button
+		deleteButton = new Button(buttonComposite, SWT.PUSH);
+	    deleteButton.setText(CachePlugin.getResourceString(_UI_BUTTON_DELETE_ENTRY));
+	    gridData = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_END);
+	    deleteButton.setLayoutData(gridData);
+	    deleteButton.addSelectionListener(new SelectionAdapter() {
+	          public void widgetSelected(SelectionEvent event) {
+              if(MessageDialog.openConfirm(Display.getDefault().getActiveShell(), CachePlugin.getResourceString(_UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_TITLE), CachePlugin.getResourceString(_UI_CONFIRM_DELETE_CACHE_ENTRY_DIALOG_MESSAGE)))
+              {
+	              String[] selectedEntries = entries.getSelection();
+				  int numSelectedEntries = selectedEntries.length;
+				  
+				  Cache cache = Cache.getInstance();
+				  for(int i = 0; i < numSelectedEntries; i++)
+				  {
+				    cache.deleteEntry(selectedEntries[i]);
+				  }
+				  String[] cacheEntries = cache.getCachedURIs();
+				  Arrays.sort(cacheEntries);
+				  entries.setItems(cacheEntries);
+          setPreferenceWidgets();
+	          }
+            }
+	       });
+		
+		// Create the Clear Cache button
+		clearButton = new Button(buttonComposite, SWT.PUSH);
+	    clearButton.setText(CachePlugin.getResourceString(_UI_BUTTON_CLEAR_CACHE));
+	    gridData = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_END);
+	    clearButton.setLayoutData(gridData);
+	    clearButton.addSelectionListener(new SelectionAdapter() {
+	          public void widgetSelected(SelectionEvent event) {
+				  if(MessageDialog.openConfirm(Display.getDefault().getActiveShell(), CachePlugin.getResourceString(_UI_CONFIRM_CLEAR_CACHE_DIALOG_TITLE), CachePlugin.getResourceString(_UI_CONFIRM_CLEAR_CACHE_DIALOG_MESSAGE)))
+				  {
+					  Cache cache = Cache.getInstance();
+					  cache.clear();
+					  String[] cacheEntries = cache.getCachedURIs();
+					  Arrays.sort(cacheEntries);
+					  entries.setItems(cacheEntries);
+            setPreferenceWidgets();
+				  }
+	          }
+	       });
+      
+      }
+      catch(Throwable e)
+      {
+        System.out.println(e);
+      }
+      setPreferenceWidgets();
+      
+		return composite;
+	}
+  
+  /**
+   * Set the preference page widgets. There are a few rules.
+   * 1. If disabled, all of the widgets are diabled except for the disabled check box.
+   * 2. If enabled, all widgets are enabled except
+   *  a. The delete button is enabled only if there is a selection in the list.
+   *  b. The clear button is enabled only if there are items in the list.
+   */
+  public void setPreferenceWidgets()
+  {
+    if(composite != null && composite.getEnabled())
+    {
+      // Cache is disabled.
+      if(enabledButton.getSelection())
+      {
+        deleteButton.setEnabled(false);
+        clearButton.setEnabled(false);
+        entriesGroup.setEnabled(false);
+        entries.setEnabled(false);
+      }
+      else
+      {
+        entriesGroup.setEnabled(true);
+        entries.setEnabled(true);
+        if(entries.getSelectionCount() > 0)
+        {
+          deleteButton.setEnabled(true);
+        }
+        else
+        {
+          deleteButton.setEnabled(false);
+        }
+        if(entries.getItemCount() > 0)
+        {
+          clearButton.setEnabled(true);
+        }
+        else
+        {
+          clearButton.setEnabled(false);
+        }
+      }
+    }
+  }
+	
+	
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/PreferenceConstants.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/PreferenceConstants.java
new file mode 100644
index 0000000..03d4610
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/PreferenceConstants.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal.preferences;
+
+/**
+ * Constant definitions for plug-in preferences
+ */
+public class PreferenceConstants 
+{
+  public static final String CACHE_ENABLED = "cacheEnabled";
+	
+}
diff --git a/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/PreferenceInitializer.java b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/PreferenceInitializer.java
new file mode 100644
index 0000000..a693a08
--- /dev/null
+++ b/plugins/org.eclipse.wst.internet.cache/src/org/eclipse/wst/internet/cache/internal/preferences/PreferenceInitializer.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.wst.internet.cache.internal.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import org.eclipse.wst.internet.cache.internal.CachePlugin;
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer 
+{
+	/**
+	 * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+	 */
+	public void initializeDefaultPreferences() 
+  {
+		IPreferenceStore store = CachePlugin.getDefault().getPreferenceStore();
+    store.setDefault(PreferenceConstants.CACHE_ENABLED, true);
+	}
+}