Tests for https://bugs.eclipse.org/bugs/show_bug.cgi?id=312512.
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/JSFCoreFastTests.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/JSFCoreFastTests.java
index a20bb8b..479cd21 100644
--- a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/JSFCoreFastTests.java
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/JSFCoreFastTests.java
@@ -1,6 +1,8 @@
 package org.eclipse.jst.jsf.core.tests;
 
 import org.eclipse.jst.jsf.core.tests.resource.AllLifecycleListenerTests;
+import org.eclipse.jst.jsf.core.tests.resource.FastClasspathEntryLifecycleTests;
+import org.eclipse.jst.jsf.core.tests.resource.TestDefaultJarLocator;
 import org.eclipse.jst.jsf.core.tests.resource.TestResourceTracker;
 import org.eclipse.jst.jsf.core.tests.serialization.TLDAttributeSerializationTests;
 import org.eclipse.jst.jsf.test.util.junit4.FastTest;
@@ -13,7 +15,8 @@
 @IncludeCategory(FastTest.class)
 @SuiteClasses(
 { AllLifecycleListenerTests.class,
-        TestResourceTracker.class, TLDAttributeSerializationTests.class })
+        TestResourceTracker.class, TLDAttributeSerializationTests.class ,
+        FastClasspathEntryLifecycleTests.class, TestDefaultJarLocator.class})
 public class JSFCoreFastTests
 {
 
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/AbstractTestListener.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/AbstractTestListener.java
new file mode 100644
index 0000000..7b808b8
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/AbstractTestListener.java
@@ -0,0 +1,12 @@
+package org.eclipse.jst.jsf.core.tests.resource;
+
+import java.util.EventObject;
+
+import org.eclipse.jst.jsf.common.internal.resource.EventResult;
+import org.eclipse.jst.jsf.common.internal.resource.ILifecycleListener;
+
+abstract class AbstractTestListener<EVENTTYPE extends EventObject> implements ILifecycleListener<EVENTTYPE>
+{
+
+    public abstract EventResult acceptEvent(final EVENTTYPE event);
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/ClasspathTestListener.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/ClasspathTestListener.java
new file mode 100644
index 0000000..d6ddd43
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/ClasspathTestListener.java
@@ -0,0 +1,121 @@
+package org.eclipse.jst.jsf.core.tests.resource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jst.jsf.common.internal.resource.ClasspathEntryLifecycleListener;
+import org.eclipse.jst.jsf.common.internal.resource.EventResult;
+import org.eclipse.jst.jsf.common.internal.resource.IClasspathLifecycleListener;
+import org.eclipse.jst.jsf.common.internal.resource.IClasspathLifecycleListener.ClasspathLifecycleEvent;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJDTWorkspaceContext;
+
+class ClasspathTestListener extends
+        AbstractTestListener<ClasspathLifecycleEvent> implements
+        IClasspathLifecycleListener
+{
+    private final List<EventData> _events = new ArrayList<EventData>();
+    private final MockJDTWorkspaceContext _jdtContext;
+
+    public ClasspathTestListener(final MockJDTWorkspaceContext jdtContext)
+    {
+        _jdtContext = jdtContext;
+    }
+
+    public ClasspathTestListener(final MockJDTWorkspaceContext jdtContext,
+            final ClasspathEntryLifecycleListener listener)
+    {
+        this(jdtContext);
+        listener.addListener(this);
+    }
+
+    public void fireAndExpect(final ElementChangedEvent fire,
+            final List<EventData> expectedData)
+    {
+        fireEvent(fire);
+        assertEquals(expectedData.size(), _events.size());
+        for (final EventData data : expectedData)
+        {
+            data.assertContainedIn(_events);
+        }
+    }
+
+    public void fireAndExpect(final ElementChangedEvent fire,
+            final IJavaElement javaElement, final ClasspathLifecycleEvent.Type type)
+    {
+        fireAndExpect(fire, Collections.singletonList(new EventData(
+                javaElement, type)));
+    }
+
+    public void fireAndExpectNull(final ElementChangedEvent fire)
+    {
+        fireEvent(fire);
+        assertTrue(_events.isEmpty());
+    }
+
+    protected void fireEvent(final ElementChangedEvent event)
+    {
+        _events.clear();
+        _jdtContext.fireElementChangedEvent(event);
+    }
+
+    public static class EventData
+    {
+        private final IJavaElement  _affectedElement;
+        private final ClasspathLifecycleEvent.Type  _type;
+
+        // private final EventType _eventType;
+        // private final ReasonType _reasonType;
+        public EventData(final IJavaElement affectedElement, final ClasspathLifecycleEvent.Type type)
+        {
+            super();
+            _affectedElement = affectedElement;
+            _type = type;
+        }
+
+        public EventData(final ClasspathLifecycleEvent event)
+        {
+            this(event.getAffectedElement(), event.getType());
+        }
+
+        public void assertContainedIn(final List<EventData> events)
+        {
+            for (final EventData event : events)
+            {
+                if (isEqual(event))
+                {
+                    return;
+                }
+            }
+            Assert.fail("Event not found in list: " + this.toString());
+        }
+
+        public boolean isEqual(final EventData eventData)
+        {
+            return (_affectedElement.equals(eventData._affectedElement)
+                        && _type == eventData._type);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format(
+                    "Classpath Entry: %s",
+                    _affectedElement.toString());
+        }
+    }
+
+    @Override
+    public EventResult acceptEvent(final ClasspathLifecycleEvent event)
+    {
+        _events.add(new EventData(event));
+        return EventResult.getDefaultEventResult();
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/FastClasspathEntryLifecycleTests.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/FastClasspathEntryLifecycleTests.java
new file mode 100644
index 0000000..0c86f4d
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/FastClasspathEntryLifecycleTests.java
@@ -0,0 +1,72 @@
+package org.eclipse.jst.jsf.core.tests.resource;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jst.jsf.common.internal.resource.ClasspathEntryLifecycleListener;
+import org.eclipse.jst.jsf.common.internal.resource.IClasspathLifecycleListener.ClasspathLifecycleEvent;
+import org.eclipse.jst.jsf.test.util.junit4.NoPluginEnvironment;
+import org.eclipse.jst.jsf.test.util.mock.MockProject;
+import org.eclipse.jst.jsf.test.util.mock.MockWorkspaceContext;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJDTWorkspaceContext;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJavaChangeEventFactory;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJavaCoreMediator;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJavaProject;
+import org.eclipse.jst.jsf.test.util.mock.java.MockPackageFragmentRoot;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(NoPluginEnvironment.class)
+public class FastClasspathEntryLifecycleTests
+{
+    private MockWorkspaceContext _wsContext;
+    private MockJavaChangeEventFactory _factory;
+    private MockProject _project;
+    private MockJDTWorkspaceContext _jdtContext;
+    private MockJavaProject _javaProject;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        _wsContext = new MockWorkspaceContext();
+        _project = _wsContext.createProject("SomeTestProject");
+        _jdtContext = new MockJDTWorkspaceContext(_wsContext);
+        _javaProject = _jdtContext.createJavaProject(_project);
+        _factory = new MockJavaChangeEventFactory(_jdtContext);
+    }
+
+    @Test
+    public void testAddJarTo()
+    {
+        final ClasspathEntryLifecycleListener listener = new ClasspathEntryLifecycleListener(
+                _project, new MockJavaCoreMediator(_jdtContext));
+        ClasspathTestListener testListener = new ClasspathTestListener(
+                _jdtContext, listener);
+        IPackageFragmentRoot fragRoot = new MockPackageFragmentRoot(
+                _javaProject, new Path(
+                        "/WebContent/WEB-INF/lib/my.jar"));
+        ElementChangedEvent event = _factory.createSimpleJarAdded(_project,
+                fragRoot);
+        testListener.fireAndExpect(event, event.getDelta().getElement(),
+                ClasspathLifecycleEvent.Type.ADDED);
+        listener.dispose();
+    }
+
+    @Test
+    public void testRemoveJarFrom()
+    {
+        final ClasspathEntryLifecycleListener listener = new ClasspathEntryLifecycleListener(
+                _project, new MockJavaCoreMediator(_jdtContext));
+        ClasspathTestListener testListener = new ClasspathTestListener(
+                _jdtContext, listener);
+        IPackageFragmentRoot fragRoot = new MockPackageFragmentRoot(
+                _javaProject, new Path(
+                        "/WebContent/WEB-INF/lib/my.jar"));
+        ElementChangedEvent event = _factory.createSimpleJarRemoved(_project,
+                fragRoot);
+        testListener.fireAndExpect(event, event.getDelta().getElement(),
+                ClasspathLifecycleEvent.Type.REMOVED);
+        listener.dispose();
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MockListener.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MockListener.java
index 0c8b5c4..f7899cf 100644
--- a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MockListener.java
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MockListener.java
@@ -17,6 +17,7 @@
 import java.util.List;
 
 import org.eclipse.core.resources.IResource;
+import org.eclipse.jst.jsf.common.internal.resource.EventResult;
 import org.eclipse.jst.jsf.common.internal.resource.IResourceLifecycleListener;
 import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent;
 import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.EventType;
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MyTestListener.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MyTestListener.java
index 7160969..88c4965 100644
--- a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MyTestListener.java
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/MyTestListener.java
@@ -11,6 +11,7 @@
 
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.jst.jsf.common.internal.resource.EventResult;
 import org.eclipse.jst.jsf.common.internal.resource.IResourceLifecycleListener;
 import org.eclipse.jst.jsf.common.internal.resource.LifecycleListener;
 import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent;
@@ -18,7 +19,7 @@
 import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.ReasonType;
 import org.eclipse.jst.jsf.test.util.mock.MockWorkspaceContext;
 
-class MyTestListener implements IResourceLifecycleListener
+class MyTestListener extends AbstractTestListener<ResourceLifecycleEvent> implements IResourceLifecycleListener
 {
     private final List<EventData> _events = new ArrayList<EventData>();
     private final MockWorkspaceContext _wsContext;
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/TestDefaultJarLocator.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/TestDefaultJarLocator.java
new file mode 100644
index 0000000..0eb8e13
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/TestDefaultJarLocator.java
@@ -0,0 +1,141 @@
+package org.eclipse.jst.jsf.core.tests.resource;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import java.io.File;
+import java.util.Collection;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jst.jsf.common.internal.resource.ClasspathJarFile;
+import org.eclipse.jst.jsf.common.internal.resource.DefaultJarLocator;
+import org.eclipse.jst.jsf.common.internal.resource.IJarLocator.JarChangeEvent;
+import org.eclipse.jst.jsf.common.internal.resource.IJarLocator.JarChangeEvent.Type;
+import org.eclipse.jst.jsf.common.internal.resource.IJarLocator.JarChangeListener;
+import org.eclipse.jst.jsf.test.util.junit4.NoPluginEnvironment;
+import org.eclipse.jst.jsf.test.util.mock.MockProject;
+import org.eclipse.jst.jsf.test.util.mock.MockWorkspaceContext;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJDTWorkspaceContext;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJavaChangeEventFactory;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJavaCoreMediator;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJavaProject;
+import org.eclipse.jst.jsf.test.util.mock.java.MockPackageFragmentRoot;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(NoPluginEnvironment.class)
+public class TestDefaultJarLocator
+{
+    private MockWorkspaceContext _wsContext;
+    private MockProject _project;
+    private MockJavaChangeEventFactory _factory;
+    private MockJDTWorkspaceContext _jdtContext;
+    private MockJavaProject _javaProject;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        _wsContext = new MockWorkspaceContext();
+        _project = _wsContext.createProject("SomeTestProject");
+        _jdtContext = new MockJDTWorkspaceContext(_wsContext);
+        _factory = new MockJavaChangeEventFactory(_jdtContext);
+        _jdtContext.createCPELibraryInProject(_project, new Path(
+                "/WEB-INF/WebContent/lib/nocareContents.jar"), new File(
+                "./testfiles/faces-all-bogus.jar"));
+        _javaProject = _jdtContext.createJavaProject(_project);
+    }
+
+    @Test
+    public void testStart() throws Exception
+    {
+        final DefaultJarLocator jarLocator = new DefaultJarLocator(
+                new MockJavaCoreMediator(_jdtContext));
+        jarLocator.start(_project);
+    }
+
+    @Test
+    public void testLocate()
+    {
+        final DefaultJarLocator jarLocator = new DefaultJarLocator(
+                new MockJavaCoreMediator(_jdtContext));
+        jarLocator.start(_project);
+        Collection<? extends ClasspathJarFile> locate = jarLocator.locate(_project);
+        assertEquals(1, locate.size());
+        Collection<? extends ClasspathJarFile> jars = jarLocator.getJars(_project);
+        assertEquals(1, locate.size());
+        assertEquals(locate, jars);
+    }
+
+    @Test
+    public void testAddJar()
+    {
+        final DefaultJarLocator jarLocator = new DefaultJarLocator(
+                new MockJavaCoreMediator(_jdtContext));
+        jarLocator.start(_project);
+        final JarChangeEvent[] trappedEvents = new JarChangeEvent[1];
+        jarLocator.addListener(new JarChangeListener()
+        {
+            @Override
+            public void changed(final JarChangeEvent event)
+            {
+                trappedEvents[0] = event;
+            }
+        });
+        IPackageFragmentRoot fragRoot = new MockPackageFragmentRoot(
+                _javaProject, new Path(
+                        "/WebContent/WEB-INF/lib/my.jar"));
+        final ElementChangedEvent event = _factory.createSimpleJarAdded(
+                _project, fragRoot);
+        _jdtContext.fireElementChangedEvent(event);
+        assertNotNull(trappedEvents[0]);
+        assertEquals(Type.JAR_ADDED, trappedEvents[0].getType());
+        assertEquals("/WebContent/WEB-INF/lib/my.jar", trappedEvents[0]
+                .getJar().getPath().toString());
+    }
+
+    @Test
+    public void testRemoveJar()
+    {
+        final DefaultJarLocator jarLocator = new DefaultJarLocator(
+                new MockJavaCoreMediator(_jdtContext));
+        jarLocator.start(_project);
+        final JarChangeEvent[] trappedEvents = new JarChangeEvent[1];
+        jarLocator.addListener(new JarChangeListener()
+        {
+            @Override
+            public void changed(final JarChangeEvent event)
+            {
+                trappedEvents[0] = event;
+            }
+        });
+        IPackageFragmentRoot fragRoot = new MockPackageFragmentRoot(
+                _javaProject, new Path(
+                        "/WebContent/WEB-INF/lib/my.jar"));
+        final ElementChangedEvent event = _factory.createSimpleJarRemoved(
+                _project, fragRoot);
+        _jdtContext.fireElementChangedEvent(event);
+        assertNotNull(trappedEvents[0]);
+        assertEquals(Type.JAR_REMOVED, trappedEvents[0].getType());
+        assertEquals("/WebContent/WEB-INF/lib/my.jar", trappedEvents[0]
+                .getJar().getPath().toString());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testLocateWithoutStart()
+    {
+        final DefaultJarLocator jarLocator = new DefaultJarLocator(
+                new MockJavaCoreMediator(_jdtContext));
+        jarLocator.locate(_project);
+    }
+    
+    @Test(expected = IllegalStateException.class)
+    public void testGetJarsWithoutStart()
+    {
+        final DefaultJarLocator jarLocator = new DefaultJarLocator(
+                new MockJavaCoreMediator(_jdtContext));
+        jarLocator.getJars(_project);
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/TestLifecycleListener.java b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/TestLifecycleListener.java
index 95dd2fb..54b6eea 100644
--- a/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/TestLifecycleListener.java
+++ b/jsf/tests/org.eclipse.jst.jsf.core.tests/src/org/eclipse/jst/jsf/core/tests/resource/TestLifecycleListener.java
@@ -18,6 +18,7 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jst.jsf.common.internal.resource.EventResult;
 import org.eclipse.jst.jsf.common.internal.resource.IResourceLifecycleListener;
 import org.eclipse.jst.jsf.common.internal.resource.LifecycleListener;
 import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent;
diff --git a/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/resources/TestJarBasedJSFResourceLocator.java b/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/resources/TestJarBasedJSFResourceLocator.java
index acf9a40..dab04fe 100644
--- a/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/resources/TestJarBasedJSFResourceLocator.java
+++ b/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/resources/TestJarBasedJSFResourceLocator.java
@@ -3,23 +3,27 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
+import java.io.File;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.jar.JarFile;
 
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jst.jsf.common.internal.locator.ILocatorChangeListener;
 import org.eclipse.jst.jsf.common.internal.resource.ContentTypeResolver;
-import org.eclipse.jst.jsf.common.internal.resource.IJarProvider;
+import org.eclipse.jst.jsf.common.internal.resource.DefaultJarLocator;
+import org.eclipse.jst.jsf.common.internal.resource.IJarLocator;
 import org.eclipse.jst.jsf.designtime.internal.resources.IJSFResourceFragment;
 import org.eclipse.jst.jsf.designtime.internal.resources.JarBasedJSFResourceLocator;
 import org.eclipse.jst.jsf.test.util.junit4.NoPluginEnvironment;
 import org.eclipse.jst.jsf.test.util.mock.MockContentTypeManager;
-import org.eclipse.jst.jsf.test.util.mock.MockJarProvider;
+import org.eclipse.jst.jsf.test.util.mock.MockFile;
 import org.eclipse.jst.jsf.test.util.mock.MockProject;
+import org.eclipse.jst.jsf.test.util.mock.MockWorkspaceContext;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJDTWorkspaceContext;
+import org.eclipse.jst.jsf.test.util.mock.java.MockJavaCoreMediator;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -27,25 +31,39 @@
 @Category(NoPluginEnvironment.class)
 public class TestJarBasedJSFResourceLocator
 {
-    private IJarProvider _jarProvider;
+    private IJarLocator _jarProvider;
     private JarBasedJSFResourceLocator _locator;
+    private MockJDTWorkspaceContext _jdtContext;
+    private MockWorkspaceContext _wsContext;
+    private MockProject _project;
+    private MockFile _jarIFile;
 
     @SuppressWarnings("unchecked")
     @Before
     public void setUp()
     {
-        final JarFile jar = MockJarProvider.getJar("./testdata/jsfResources.jar");
-        _jarProvider = new MockJarProvider(jar);
-        _locator = new JarBasedJSFResourceLocator(Collections.EMPTY_LIST, new CopyOnWriteArrayList<ILocatorChangeListener>(), _jarProvider, new ContentTypeResolver(new MockContentTypeManager()));
+        _wsContext = new MockWorkspaceContext();
+        _project = _wsContext.createProject("TestProject");
+        File jarFile = new File("./testdata/jsfResources.jar");
+        assertTrue(jarFile.exists());
+        _jdtContext = new MockJDTWorkspaceContext(_wsContext);
+        _jdtContext.createCPELibraryInProject(_project, new Path(
+                "/WebContent/WEB-INF/lib/jsfResources.jar"), jarFile);
+        _jarProvider = new DefaultJarLocator(new MockJavaCoreMediator(
+                _jdtContext));
+        _locator = new JarBasedJSFResourceLocator(Collections.EMPTY_LIST,
+                new CopyOnWriteArrayList<ILocatorChangeListener>(),
+                _jarProvider, new ContentTypeResolver(
+                        new MockContentTypeManager()));
     }
 
     @Test
     public void testLocate()
     {
         
-        _locator.start(new MockProject(new Path("foo"), null));
+        _locator.start(_project);
         // we can pass null here since our jar provider doesn't care about projects.
-        final List<IJSFResourceFragment> foundResources = _locator.locate(null);
+        final List<IJSFResourceFragment> foundResources = _locator.locate(_project);
         assertEquals(2, foundResources.size());
         final Set<String> foundResourceIds = new HashSet<String>();
         for (final IJSFResourceFragment res : foundResources)
diff --git a/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/views/persistence/TestSerializableTLDTagElement.java b/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/views/persistence/TestSerializableTLDTagElement.java
index 9bd9a7e..a71a04e 100644
--- a/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/views/persistence/TestSerializableTLDTagElement.java
+++ b/jsf/tests/org.eclipse.jst.jsf.designtime.tests/src/org/eclipse/jst/jsf/designtime/tests/views/persistence/TestSerializableTLDTagElement.java
@@ -43,15 +43,12 @@
                         "jst.web").getVersion("2.4"));
         _webProject.createFromZip(zipFile, true);
         */
-        final ZipFile zipFile = JSFTestUtil.createZipFile(
-        		TestsPlugin.getDefault().getBundle(),
-        		"/testfiles/testzips/TLDTests2.zip");
-        _webProject = new WebProjectTestEnvironment(
-        		this,
-        		JavaFacet.VERSION_1_5,
-        		ProjectFacetsManager.getProjectFacet("jst.web").getVersion("2.4"));
+        final ZipFile zipFile = JSFTestUtil.createZipFile(TestsPlugin
+                .getDefault().getBundle(), "/testfiles/testzips/TLDTests2.zip");
+        _webProject = new WebProjectTestEnvironment(this,
+                JavaFacet.VERSION_1_5, ProjectFacetsManager.getProjectFacet(
+                        "jst.web").getVersion("2.4"));
         _webProject.createFromZip2(zipFile, true);
-
         assertNotNull(_webProject);
 
         _sampleTldElementDeclaration = findElementDeclaration(_webProject
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/META-INF/MANIFEST.MF b/jsf/tests/org.eclipse.jst.jsf.test.util/META-INF/MANIFEST.MF
index 80986ac..1132212 100644
--- a/jsf/tests/org.eclipse.jst.jsf.test.util/META-INF/MANIFEST.MF
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/META-INF/MANIFEST.MF
@@ -33,7 +33,8 @@
  org.eclipse.jst.jsf.common;bundle-version="1.2.0"
 Export-Package: org.eclipse.jst.jsf.test.util,
  org.eclipse.jst.jsf.test.util.junit4,
- org.eclipse.jst.jsf.test.util.mock
+ org.eclipse.jst.jsf.test.util.mock,
+ org.eclipse.jst.jsf.test.util.mock.java
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Bundle-Vendor: %Bundle-Vendor.0
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockContainer.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockContainer.java
index 16a1694..5880c2b 100644
--- a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockContainer.java
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockContainer.java
@@ -26,7 +26,7 @@
 
     public void loadAllMembers() throws Exception 
     {
-        _resFactory.forceLoad((MockProject) this.getProject());
+        getResFactory().forceLoad((MockProject) this.getProject());
     }
     
     @Override
@@ -34,7 +34,7 @@
     {
         try
         {
-            _resFactory.dispose();
+            getResFactory().dispose();
         } finally
         {
             super.dispose();
@@ -81,7 +81,7 @@
     {
         try
         {
-            return (IFile) _resFactory.createFile(this, path);
+            return (IFile) getResFactory().createFile(this, path);
         } catch (Exception e)
         {
             throw new AssertionFailedError(e.getLocalizedMessage());
@@ -97,7 +97,7 @@
     {
         try
         {
-            return _resFactory.createFolder(this, path);
+            return getResFactory().createFolder(this, path);
         } catch (Exception e)
         {
             throw new AssertionFailedError(e.getLocalizedMessage());
@@ -127,8 +127,8 @@
 
     public IResource[] members(int memberFlags) throws CoreException
     {
-        // ignore member flags for now
-        return _resFactory.getCurrentMembers(this).toArray(new IResource[0]);
+        // TODO: ignore member flags for now
+        return getResFactory().getCurrentMembers(this).toArray(new IResource[0]);
     }
 
     public IFile[] findDeletedMembersWithHistory(int depth,
@@ -160,7 +160,7 @@
         throw new UnsupportedOperationException();
     }
 
-    public final IMockResourceFactory getResFactory()
+    public IMockResourceFactory getResFactory()
     {
         return _resFactory;
     }
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockFile.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockFile.java
index 1cb307c..da3c413 100644
--- a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockFile.java
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockFile.java
@@ -1,7 +1,10 @@
 package org.eclipse.jst.jsf.test.util.mock;
 
+import static junit.framework.Assert.assertTrue;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
@@ -14,6 +17,7 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.content.IContentDescription;
 import org.eclipse.jst.jsf.test.util.Activator;
@@ -23,6 +27,7 @@
 {
 
     private byte[]  _contents;
+    private File    _concreteFile;
 
     public MockFile(final IPath path)
     {
@@ -156,11 +161,17 @@
         try
         {
             captureBytes = JSFTestUtil.loadFromInputStream(source);
+            // keep concrete file in sync if we have one.
+            if (_concreteFile != null && _concreteFile.exists())
+            {
+                JSFTestUtil.saveToFileSystem(captureBytes.toByteArray(), _concreteFile.toURI());
+            }
         } catch (IOException e)
         {
             throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed loading mock contents from stream"));
         }
         _contents = captureBytes.toByteArray();
+        
     }
 
     public void setContents(final IFileState source, final boolean force,
@@ -181,4 +192,33 @@
     {
         setContents(source, (updateFlags | IResource.FORCE)!= 0, (updateFlags | IResource.KEEP_HISTORY) != 0, monitor);
     }
+
+    @Override
+    public IPath getLocation()
+    {
+        File concreteFile = ensureConcreteFile();
+        return Path.fromOSString(concreteFile.getAbsolutePath());
+    }
+
+    private File ensureConcreteFile()
+    {
+        if (_concreteFile == null)
+        {
+            String tempFileName = getFullPath().toString().replace('/', '_');
+            try
+            {
+                _concreteFile = File.createTempFile(tempFileName, "."+getFullPath().getFileExtension());
+                _concreteFile.deleteOnExit();
+                assertTrue(_concreteFile.exists());
+                if (_contents != null)
+                {
+                    JSFTestUtil.saveToFileSystem(_contents, _concreteFile.toURI());
+                }
+            } catch (IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+        return _concreteFile;
+    }
 }
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockJarProvider.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockJarProvider.java
index 0332004..dad33fc 100644
--- a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockJarProvider.java
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockJarProvider.java
@@ -6,61 +6,16 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
 import java.util.jar.JarFile;
 
 import junit.framework.AssertionFailedError;
 
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IResourceVisitor;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jst.jsf.common.internal.resource.IJarProvider;
 import org.eclipse.jst.jsf.test.util.JSFTestUtil;
 
-public final class MockJarProvider implements IJarProvider
+public final class MockJarProvider
 {
-    private final List<JarFile> _jarFiles;
-
-    public MockJarProvider(final JarFile jarFile)
-    {
-        this(Collections.singletonList(jarFile));
-    }
-
-    public MockJarProvider(final MockProject project) throws CoreException
-    {
-        final List<JarFile> jarFiles = new ArrayList<JarFile>();
-        project.accept(new IResourceVisitor()
-        {
-            public boolean visit(final IResource resource) throws CoreException
-            {
-                if (resource.getType() == IResource.FILE
-                        && "jar".equals(resource.getFullPath()
-                                .getFileExtension()))
-                {
-                    final JarFile jarFile = getJar((IFile) resource);
-                    jarFiles.add(jarFile);
-                }
-                return true;
-            }
-        });
-        _jarFiles = jarFiles;
-    }
-
-    public MockJarProvider(final List<JarFile> jarFiles)
-    {
-        _jarFiles = jarFiles;
-    }
-
-    public Collection<JarFile> getJars(final IProject project)
-    {
-        return _jarFiles;
-    }
-
     public static JarFile getJar(final String fileName)
             throws AssertionFailedError
     {
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceContext.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceContext.java
index ec4f367..5aa4dc8 100644
--- a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceContext.java
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceContext.java
@@ -1,5 +1,10 @@
 package org.eclipse.jst.jsf.test.util.mock;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -26,13 +31,13 @@
 public class MockWorkspaceContext
 {
     private final MockWorkspace _ws;
-
     private final Map<IPath, MockResource> _ownedResources;
 
     public MockWorkspaceContext(final MockWorkspace ws)
     {
         _ws = ws;
         _ownedResources = new HashMap<IPath, MockResource>();
+        ((MockWorkspaceRoot)ws.getRoot()).setContext(this);
     }
 
     public MockWorkspaceContext()
@@ -91,13 +96,11 @@
     public MockProject createProject(final String baseId)
     {
         int i = 0;
-
         while (_ownedResources.get(generateName(baseId, i)) != null)
         {
             // keep looping until we get TestProject_i that doesn't exist
             i++;
         }
-
         return createProject(generateName(baseId, i), false);
     }
 
@@ -134,10 +137,45 @@
         return project;
     }
 
+    public MockFile attachFile(MockProject project, IPath projectRelativePath,
+            File file)
+    {
+        assertEquals(checkExists(project.getFullPath(), true), project);
+        // throw an exception if projectRelativePath already exists
+        checkExists(project.getFullPath().append(projectRelativePath), false);
+        assertTrue(file.exists());
+        MockFile iFile = (MockFile) project.getFile(projectRelativePath);
+        InputStream inStream = null;
+        try
+        {
+            inStream = new FileInputStream(file);
+            iFile.setContents(inStream, 0, null);
+            return iFile;
+        } catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        } catch (CoreException e)
+        {
+            throw new RuntimeException(e);
+        }
+        finally
+        {
+            if (inStream != null)
+            {
+                try
+                {
+                    inStream.close();
+                } catch (IOException e)
+                {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
     private MockResource checkExists(final IPath path, final boolean replace)
     {
         final MockResource resource = _ownedResources.get(path);
-
         if (resource != null && !replace)
         {
             throw new IllegalArgumentException(path.toString()
@@ -171,7 +209,6 @@
             MockResource resource = checkExists(newFileFullPath, true);
             if (resource == null)
             {
-
                 resource = new MockFile(newFileFullPath);
                 ((MockResource) resource).setWorkspace(_ws);
                 ((MockResource) resource).setProject(container.getProject());
@@ -179,7 +216,6 @@
                 {
                     final ZipEntry entry = _zip.getEntry(_pathIntoZip
                             + path.toString());
-
                     if (entry != null)
                     {
                         final InputStream inputStream = _zip
@@ -190,7 +226,6 @@
                                     false, true, new NullProgressMonitor());
                         }
                     }
-
                     ensurePathToNewResource(container, path);
                 }
                 _ownedResources.put(newFileFullPath, resource);
@@ -205,7 +240,6 @@
             MockResource resource = checkExists(newFileFullPath, true);
             if (resource == null)
             {
-
                 resource = new MockFolder(newFileFullPath, this);
                 ((MockResource) resource).setWorkspace(_ws);
                 ((MockResource) resource).setProject(container.getProject());
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceRoot.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceRoot.java
index 95c55a3..136515b 100644
--- a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceRoot.java
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/MockWorkspaceRoot.java
@@ -14,72 +14,77 @@
 
 public class MockWorkspaceRoot extends MockContainer implements IWorkspaceRoot
 {
+    private MockWorkspaceContext _wsContext;
 
     public MockWorkspaceRoot()
     {
         super(IResource.ROOT, new Path(""), null);
     }
 
-    public void delete(boolean deleteContent, boolean force,
-            IProgressMonitor monitor) throws CoreException
+    public void setContext(MockWorkspaceContext context)
+    {
+        _wsContext = context;
+    }
+
+    public void delete(final boolean deleteContent, final boolean force,
+            final IProgressMonitor monitor) throws CoreException
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IContainer[] findContainersForLocation(IPath location)
+    public IContainer[] findContainersForLocation(final IPath location)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IContainer[] findContainersForLocationURI(URI location)
+    public IContainer[] findContainersForLocationURI(final URI location)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IContainer[] findContainersForLocationURI(URI location,
-            int memberFlags)
+    public IContainer[] findContainersForLocationURI(final URI location,
+            final int memberFlags)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IFile[] findFilesForLocation(IPath location)
+    public IFile[] findFilesForLocation(final IPath location)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IFile[] findFilesForLocationURI(URI location)
+    public IFile[] findFilesForLocationURI(final URI location)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IFile[] findFilesForLocationURI(URI location, int memberFlags)
+    public IFile[] findFilesForLocationURI(final URI location, final int memberFlags)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IContainer getContainerForLocation(IPath location)
+    public IContainer getContainerForLocation(final IPath location)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IFile getFileForLocation(IPath location)
+    public IFile getFileForLocation(final IPath location)
     {
         throw new UnsupportedOperationException();
         
     }
 
-    public IProject getProject(String name)
+    public IProject getProject(final String name)
     {
-        throw new UnsupportedOperationException();
-        
+        return _wsContext.getProject(new Path(name));
     }
 
     public IProject[] getProjects()
@@ -88,7 +93,7 @@
         
     }
 
-    public IProject[] getProjects(int memberFlags)
+    public IProject[] getProjects(final int memberFlags)
     {
         throw new UnsupportedOperationException();
         
@@ -105,4 +110,19 @@
     {
         return null;
     }
+
+    @Override
+    public IFile getFile(IPath path)
+    {
+        if (path == null || path.segmentCount() == 0)
+        {
+            throw new IllegalArgumentException();
+        }
+        IProject project = getProject(path.segment(0));
+        if (project != null)
+        {
+            return project.getFile(path.removeFirstSegments(1));
+        }
+        return null;
+    }
 }
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockClasspathEntry.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockClasspathEntry.java
new file mode 100644
index 0000000..8c916a5
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockClasspathEntry.java
@@ -0,0 +1,328 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IAccessRule;
+import org.eclipse.jdt.core.IClasspathAttribute;
+import org.eclipse.jdt.core.IClasspathEntry;
+
+public class MockClasspathEntry implements IClasspathEntry
+{
+    private final int _entryKind;
+    private final IPath _path;
+
+    public MockClasspathEntry(final int entryKind, final IPath path)
+    {
+        _entryKind = entryKind;
+        _path = path;
+        switch (entryKind)
+        {
+            case IClasspathEntry.CPE_CONTAINER:
+            case IClasspathEntry.CPE_LIBRARY:
+            case IClasspathEntry.CPE_PROJECT:
+            case IClasspathEntry.CPE_SOURCE:
+            case IClasspathEntry.CPE_VARIABLE:
+                // do nothing
+            break;
+            default:
+                throw new IllegalArgumentException("entryKind must be valid: "
+                        + _entryKind);
+        }
+    }
+
+    public boolean combineAccessRules()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IAccessRule[] getAccessRules()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public int getContentKind()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public int getEntryKind()
+    {
+        return _entryKind;
+    }
+
+    public IPath[] getExclusionPatterns()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IClasspathAttribute[] getExtraAttributes()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPath[] getInclusionPatterns()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPath getOutputLocation()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPath getPath()
+    {
+        return _path;
+    }
+
+    public IPath getSourceAttachmentPath()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPath getSourceAttachmentRootPath()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IClasspathEntry getReferencingEntry()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isExported()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IClasspathEntry getResolvedEntry()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString()
+    {
+        final StringBuffer buffer = new StringBuffer();
+        buffer.append(getPath());
+        buffer.append('[');
+        switch (getEntryKind())
+        {
+            case IClasspathEntry.CPE_LIBRARY:
+                buffer.append("CPE_LIBRARY"); //$NON-NLS-1$
+            break;
+            case IClasspathEntry.CPE_PROJECT:
+                buffer.append("CPE_PROJECT"); //$NON-NLS-1$
+            break;
+            case IClasspathEntry.CPE_SOURCE:
+                buffer.append("CPE_SOURCE"); //$NON-NLS-1$
+            break;
+            case IClasspathEntry.CPE_VARIABLE:
+                buffer.append("CPE_VARIABLE"); //$NON-NLS-1$
+            break;
+            case IClasspathEntry.CPE_CONTAINER:
+                buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
+            break;
+        }
+        buffer.append("]"); //$NON-NLS-1$
+        // switch (getContentKind())
+        // {
+        // case IPackageFragmentRoot.K_BINARY:
+        //                buffer.append("K_BINARY"); //$NON-NLS-1$
+        // break;
+        // case IPackageFragmentRoot.K_SOURCE:
+        //                buffer.append("K_SOURCE"); //$NON-NLS-1$
+        // break;
+        // case ClasspathEntry.K_OUTPUT:
+        //                buffer.append("K_OUTPUT"); //$NON-NLS-1$
+        // break;
+        // }
+        // buffer.append(']');
+        // if (getSourceAttachmentPath() != null)
+        // {
+        //            buffer.append("[sourcePath:"); //$NON-NLS-1$
+        // buffer.append(getSourceAttachmentPath());
+        // buffer.append(']');
+        // }
+        // if (getSourceAttachmentRootPath() != null)
+        // {
+        //            buffer.append("[rootPath:"); //$NON-NLS-1$
+        // buffer.append(getSourceAttachmentRootPath());
+        // buffer.append(']');
+        // }
+        //        buffer.append("[isExported:"); //$NON-NLS-1$
+        // buffer.append(this.isExported);
+        // buffer.append(']');
+        // IPath[] patterns = this.inclusionPatterns;
+        // int length;
+        // if ((length = patterns == null ? 0 : patterns.length) > 0)
+        // {
+        //            buffer.append("[including:"); //$NON-NLS-1$
+        // for (int i = 0; i < length; i++)
+        // {
+        // buffer.append(patterns[i]);
+        // if (i != length - 1)
+        // {
+        // buffer.append('|');
+        // }
+        // }
+        // buffer.append(']');
+        // }
+        // patterns = this.exclusionPatterns;
+        // if ((length = patterns == null ? 0 : patterns.length) > 0)
+        // {
+        //            buffer.append("[excluding:"); //$NON-NLS-1$
+        // for (int i = 0; i < length; i++)
+        // {
+        // buffer.append(patterns[i]);
+        // if (i != length - 1)
+        // {
+        // buffer.append('|');
+        // }
+        // }
+        // buffer.append(']');
+        // }
+        // if (this.accessRuleSet != null)
+        // {
+        // buffer.append('[');
+        // buffer.append(this.accessRuleSet.toString(false/* on one line */));
+        // buffer.append(']');
+        // }
+        // if (this.entryKind == CPE_PROJECT)
+        // {
+        //            buffer.append("[combine access rules:"); //$NON-NLS-1$
+        // buffer.append(this.combineAccessRules);
+        // buffer.append(']');
+        // }
+        // if (getOutputLocation() != null)
+        // {
+        //            buffer.append("[output:"); //$NON-NLS-1$
+        // buffer.append(getOutputLocation());
+        // buffer.append(']');
+        // }
+        // if ((length = this.extraAttributes == null ? 0
+        // : this.extraAttributes.length) > 0)
+        // {
+        //            buffer.append("[attributes:"); //$NON-NLS-1$
+        // for (int i = 0; i < length; i++)
+        // {
+        // buffer.append(this.extraAttributes[i]);
+        // if (i != length - 1)
+        // {
+        // buffer.append(',');
+        // }
+        // }
+        // buffer.append(']');
+        // }
+        return buffer.toString();
+    }
+
+    /**
+     * Returns true if the given object is a classpath entry with equivalent
+     * attributes.
+     */
+    @Override
+    public boolean equals(final Object object)
+    {
+        if (this == object)
+        {
+            return true;
+        }
+        if (object instanceof MockClasspathEntry)
+        {
+            final MockClasspathEntry otherEntry = (MockClasspathEntry) object;
+            // if (this.contentKind != otherEntry.getContentKind())
+            // {
+            // return false;
+            // }
+            if (this._entryKind != otherEntry.getEntryKind())
+            {
+                return false;
+            }
+            // if (this.isExported != otherEntry.isExported())
+            // {
+            // return false;
+            // }
+            if (!this._path.equals(otherEntry.getPath()))
+            {
+                return false;
+            }
+            // IPath otherPath = otherEntry.getSourceAttachmentPath();
+            // if (this.sourceAttachmentPath == null) {
+            // if (otherPath != null)
+            // {
+            // return false;
+            // }
+            // } else {
+            // if (!this.sourceAttachmentPath.equals(otherPath))
+            // {
+            // return false;
+            // }
+            // }
+            //
+            // otherPath = otherEntry.getSourceAttachmentRootPath();
+            // if (this.sourceAttachmentRootPath == null) {
+            // if (otherPath != null)
+            // {
+            // return false;
+            // }
+            // } else {
+            // if (!this.sourceAttachmentRootPath.equals(otherPath))
+            // {
+            // return false;
+            // }
+            // }
+            //
+            // if (!equalPatterns(this.inclusionPatterns,
+            // otherEntry.getInclusionPatterns()))
+            // {
+            // return false;
+            // }
+            // if (!equalPatterns(this.exclusionPatterns,
+            // otherEntry.getExclusionPatterns()))
+            // {
+            // return false;
+            // }
+            // final AccessRuleSet otherRuleSet = otherEntry.getAccessRuleSet();
+            // if (getAccessRuleSet() != null) {
+            // if (!getAccessRuleSet().equals(otherRuleSet))
+            // {
+            // return false;
+            // }
+            // } else if (otherRuleSet != null)
+            // {
+            // return false;
+            // }
+            // if (this.combineAccessRules != otherEntry.combineAccessRules())
+            // {
+            // return false;
+            // }
+            // otherPath = otherEntry.getOutputLocation();
+            // if (this.specificOutputLocation == null) {
+            // if (otherPath != null)
+            // {
+            // return false;
+            // }
+            // } else {
+            // if (!this.specificOutputLocation.equals(otherPath))
+            // {
+            // return false;
+            // }
+            // }
+            // if (!equalAttributes(this.extraAttributes,
+            // otherEntry.getExtraAttributes()))
+            // {
+            // return false;
+            // }
+            return true;
+        } else
+        {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return _path.hashCode();
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJDTWorkspaceContext.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJDTWorkspaceContext.java
new file mode 100644
index 0000000..645e05b
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJDTWorkspaceContext.java
@@ -0,0 +1,135 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IElementChangedListener;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jst.jsf.test.util.mock.MockFile;
+import org.eclipse.jst.jsf.test.util.mock.MockProject;
+import org.eclipse.jst.jsf.test.util.mock.MockWorkspaceContext;
+
+public class MockJDTWorkspaceContext
+{
+    private final MockWorkspaceContext _wsContext;
+    private final Map<MockProject, List<IPackageFragmentRoot>> _cpEntriesByProject;
+    private final CopyOnWriteArrayList<IElementChangedListener> _listeners = new CopyOnWriteArrayList<IElementChangedListener>();
+
+    public MockJDTWorkspaceContext(final MockWorkspaceContext wsContext)
+    {
+        _wsContext = wsContext;
+        _cpEntriesByProject = new HashMap<MockProject, List<IPackageFragmentRoot>>();
+    }
+
+    @SuppressWarnings("unchecked")
+    public MockJavaProject createJavaProject(final IProject project)
+    {
+        List<IPackageFragmentRoot> cpEntries = _cpEntriesByProject.get(project);
+        return new MockJavaProject(project,
+                cpEntries != null ? Collections.unmodifiableList(cpEntries)
+                        : Collections.EMPTY_LIST);
+    }
+
+    /**
+     * Initializes this context with mock cp entry information for the provider
+     * project based on the contents of the project (i.e. jar files).
+     * 
+     * @param project
+     * @throws CoreException
+     */
+    public void loadCPEntriesFromProject(final IProject project)
+            throws CoreException
+    {
+        project.accept(new IResourceVisitor()
+        {
+            public boolean visit(final IResource resource) throws CoreException
+            {
+                if (resource.getType() == IResource.FILE
+                        && "jar".equals(resource.getFullPath()
+                                .getFileExtension()))
+                {
+                    createAndAddPackageFragmentRoot((MockProject) project,
+                            ((MockFile) resource).getLocation());
+                }
+                return true;
+            }
+        });
+    }
+
+    /**
+     * @param project
+     * @param projectRelativePath
+     * @param file
+     * @return a new mock classpath entry. This entry will automatically be
+     *         added to project as a file and to any MockJavaProject created
+     *         through this context for project.
+     */
+    public IPackageFragmentRoot createCPELibraryInProject(
+            final MockProject project, final IPath projectRelativePath,
+            final File file)
+    {
+        _wsContext.attachFile(project, projectRelativePath, file);
+        return createAndAddPackageFragmentRoot(project,
+                new Path(file.getAbsolutePath()));
+    }
+
+    private IPackageFragmentRoot createAndAddPackageFragmentRoot(
+            final MockProject project, final IPath absPathToRoot)
+    {
+        final IJavaProject javaProject = createJavaProject(project);
+        final IPackageFragmentRoot fragRoot = new MockPackageFragmentRoot(
+                javaProject, absPathToRoot);
+        addCPEntry(project, fragRoot);
+        return fragRoot;
+    }
+
+    private void addCPEntry(final MockProject project,
+            final IPackageFragmentRoot packageRoot)
+    {
+        List<IPackageFragmentRoot> entriesForProject = _cpEntriesByProject
+                .get(project);
+        if (entriesForProject == null)
+        {
+            entriesForProject = new ArrayList<IPackageFragmentRoot>();
+            _cpEntriesByProject.put(project, entriesForProject);
+        }
+        entriesForProject.add(packageRoot);
+    }
+
+    public void addElementChangedListener(IElementChangedListener listener)
+    {
+        _listeners.addIfAbsent(listener);
+    }
+
+    public void removeElementChangedListener(IElementChangedListener listener)
+    {
+        _listeners.remove(listener);
+    }
+
+    public void fireElementChangedEvent(final ElementChangedEvent event)
+    {
+        for (final IElementChangedListener listener : _listeners)
+        {
+            listener.elementChanged(event);
+        }
+    }
+
+    public Collection<IElementChangedListener> getListeners()
+    {
+        return Collections.unmodifiableList(_listeners);
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaChangeEventFactory.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaChangeEventFactory.java
new file mode 100644
index 0000000..cf25ee5
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaChangeEventFactory.java
@@ -0,0 +1,47 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import static junit.framework.Assert.assertNotNull;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jst.jsf.test.util.mock.MockProject;
+
+public class MockJavaChangeEventFactory
+{
+    private final MockJDTWorkspaceContext _jdtContext;
+
+    public MockJavaChangeEventFactory(final MockJDTWorkspaceContext jdtContext)
+    {
+        _jdtContext = jdtContext;
+    }
+
+    public ElementChangedEvent createSimpleJarAdded(final IProject project,
+            final IPackageFragmentRoot packageRoots)
+    {
+        final IJavaElementDelta delta = createSimpleJarAddedDelta(project,
+                packageRoots, IJavaElementDelta.F_ADDED_TO_CLASSPATH);
+        return new ElementChangedEvent(delta, ElementChangedEvent.POST_CHANGE);
+    }
+
+    public ElementChangedEvent createSimpleJarRemoved(
+            final MockProject project, final IPackageFragmentRoot packageRoots)
+    {
+        final IJavaElementDelta delta = createSimpleJarAddedDelta(project,
+                packageRoots, IJavaElementDelta.F_REMOVED_FROM_CLASSPATH);
+        return new ElementChangedEvent(delta, ElementChangedEvent.POST_CHANGE);
+    }
+
+    public IJavaElementDelta createSimpleJarAddedDelta(final IProject project,
+            final IPackageFragmentRoot packageRoots, final int flags)
+    {
+        final IJavaProject owningProject = _jdtContext
+                .createJavaProject(project);
+        assertNotNull(owningProject);
+        final MockJavaElementDelta delta = new MockJavaElementDelta(packageRoots);
+        delta.changed(flags);
+        return delta;
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaCoreMediator.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaCoreMediator.java
new file mode 100644
index 0000000..5caf3a2
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaCoreMediator.java
@@ -0,0 +1,37 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jdt.core.IElementChangedListener;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jst.jsf.common.internal.resource.ClasspathEntryLifecycleListener;
+import org.eclipse.jst.jsf.common.internal.resource.JavaCoreMediator;
+import org.eclipse.jst.jsf.test.util.mock.MockProject;
+
+public class MockJavaCoreMediator extends JavaCoreMediator
+{
+    private final MockJDTWorkspaceContext _jdtContext;
+
+    public MockJavaCoreMediator(final MockJDTWorkspaceContext jdtContext)
+    {
+        _jdtContext = jdtContext;
+    }
+
+    @Override
+    public IJavaProject create(final IProject project)
+    {
+        return _jdtContext.createJavaProject((MockProject) project);
+    }
+
+    @Override
+    public void addElementChangedListener(IElementChangedListener listener)
+    {
+        _jdtContext.addElementChangedListener(listener);
+    }
+
+    @Override
+    public void removeElementChangeListener(
+            ClasspathEntryLifecycleListener listener)
+    {
+        _jdtContext.removeElementChangedListener(listener);
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaElement.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaElement.java
new file mode 100644
index 0000000..60a4d46
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaElement.java
@@ -0,0 +1,161 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaModel;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IOpenable;
+import org.eclipse.jdt.core.JavaModelException;
+
+public class MockJavaElement implements IJavaElement
+{
+    private boolean _exists;
+    private final IJavaProject _owningProject;
+    private String _name;
+    private final IPath  _path;
+
+    public MockJavaElement(final IJavaProject owningProject,
+            final IPath path)
+    {
+        _owningProject = owningProject;
+        _name = path.toString();
+        _path = path;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public Object getAdapter(final Class adapter)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean exists()
+    {
+        return _exists;
+    }
+
+    public final void setExists(final boolean exists)
+    {
+        _exists = exists;
+    }
+
+    public IJavaElement getAncestor(final int ancestorType)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getAttachedJavadoc(final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IResource getCorrespondingResource() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getElementName()
+    {
+        return _name;
+    }
+
+    public int getElementType()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getHandleIdentifier()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IJavaModel getJavaModel()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IJavaProject getJavaProject()
+    {
+        return _owningProject;
+    }
+
+    public IOpenable getOpenable()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IJavaElement getParent()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPath getPath()
+    {
+        return _path;
+    }
+
+    public IJavaElement getPrimaryElement()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IResource getResource()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public ISchedulingRule getSchedulingRule()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IResource getUnderlyingResource() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isReadOnly()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isStructureKnown() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean equals(final Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+        // Java model parent is null
+        // if (this.parent == null) return super.equals(o);
+        // assume instanceof check is done in subclass
+        final MockJavaElement other = (MockJavaElement) o;
+        return getElementName().equals(other.getElementName())/*
+                                                               * &&
+                                                               * this.parent.equals
+                                                               * (other.parent)
+                                                               */;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return _name.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format(
+                "MockJavaElement: name=%s, owningProject=%s, exists=%s", _name,
+                _owningProject, _exists);
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaElementDelta.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaElementDelta.java
new file mode 100644
index 0000000..7359893
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaElementDelta.java
@@ -0,0 +1,12 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.JavaElementDelta;
+
+public class MockJavaElementDelta extends JavaElementDelta
+{
+    public MockJavaElementDelta(IJavaElement element)
+    {
+        super(element);
+    }
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaProject.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaProject.java
new file mode 100644
index 0000000..3de325d
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockJavaProject.java
@@ -0,0 +1,462 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.IBuffer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IRegion;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeHierarchy;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.core.eval.IEvaluationContext;
+
+public class MockJavaProject extends MockJavaElement implements IJavaProject
+{
+    private final IProject _project;
+    private final List<IPackageFragmentRoot> _packageFragRoots;
+
+
+    public MockJavaProject(final IProject project, final List<IPackageFragmentRoot> packageFragRoots)
+    {
+        super(null, project.getFullPath());
+        _project = project;
+        _packageFragRoots = new ArrayList<IPackageFragmentRoot>(packageFragRoots);
+    }
+
+    public IJavaElement[] getChildren() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean hasChildren() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void close() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public String findRecommendedLineSeparator() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IBuffer getBuffer() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public boolean hasUnsavedChanges() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public boolean isConsistent() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public boolean isOpen()
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void makeConsistent(final IProgressMonitor progress)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void open(final IProgressMonitor progress) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void save(final IProgressMonitor progress, final boolean force)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IClasspathEntry decodeClasspathEntry(final String encodedEntry)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public String encodeClasspathEntry(final IClasspathEntry classpathEntry)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IJavaElement findElement(final IPath path) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IJavaElement findElement(final IPath path, final WorkingCopyOwner owner)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IJavaElement findElement(final String bindingKey, final WorkingCopyOwner owner)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragment findPackageFragment(final IPath path)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragmentRoot findPackageFragmentRoot(final IPath path)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragmentRoot[] findPackageFragmentRoots(final IClasspathEntry entry)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String fullyQualifiedName) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String fullyQualifiedName,
+            final IProgressMonitor progressMonitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String fullyQualifiedName, final WorkingCopyOwner owner)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String fullyQualifiedName, final WorkingCopyOwner owner,
+            final IProgressMonitor progressMonitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String packageName, final String typeQualifiedName)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String packageName, final String typeQualifiedName,
+            final IProgressMonitor progressMonitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String packageName, final String typeQualifiedName,
+            final WorkingCopyOwner owner) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IType findType(final String packageName, final String typeQualifiedName,
+            final WorkingCopyOwner owner, final IProgressMonitor progressMonitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragmentRoot[] getAllPackageFragmentRoots()
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public Object[] getNonJavaResources() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public String getOption(final String optionName, final boolean inheritJavaCoreOptions)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    @SuppressWarnings("rawtypes")
+    public Map getOptions(final boolean inheritJavaCoreOptions)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPath getOutputLocation() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragmentRoot getPackageFragmentRoot(
+            final String externalLibraryPath)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragmentRoot getPackageFragmentRoot(final IResource resource)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragmentRoot[] getPackageFragmentRoots()
+            throws JavaModelException
+    {
+        return _packageFragRoots.toArray(new IPackageFragmentRoot[0]);
+
+    }
+
+    public IPackageFragmentRoot[] getPackageFragmentRoots(final IClasspathEntry entry)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPackageFragment[] getPackageFragments() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IProject getProject()
+    {
+        return _project;
+    }
+
+    public IClasspathEntry[] getRawClasspath() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public String[] getRequiredProjectNames() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IClasspathEntry[] getResolvedClasspath(final boolean ignoreUnresolvedEntry)
+            throws JavaModelException
+    {
+        return _packageFragRoots.toArray(new IClasspathEntry[0]);
+    }
+
+    public boolean hasBuildState()
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public boolean hasClasspathCycle(final IClasspathEntry[] entries)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public boolean isOnClasspath(final IJavaElement element)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public boolean isOnClasspath(final IResource resource)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IEvaluationContext newEvaluationContext()
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public ITypeHierarchy newTypeHierarchy(final IRegion region,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public ITypeHierarchy newTypeHierarchy(final IRegion region,
+            final WorkingCopyOwner owner, final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public ITypeHierarchy newTypeHierarchy(final IType type, final IRegion region,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public ITypeHierarchy newTypeHierarchy(final IType type, final IRegion region,
+            final WorkingCopyOwner owner, final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IPath readOutputLocation()
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IClasspathEntry[] readRawClasspath()
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void setOption(final String optionName, final String optionValue)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    @SuppressWarnings("rawtypes")
+    public void setOptions(final Map newOptions)
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void setOutputLocation(final IPath path, final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void setRawClasspath(final IClasspathEntry[] entries,
+            final IPath outputLocation, final boolean canModifyResources,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void setRawClasspath(final IClasspathEntry[] entries,
+            final boolean canModifyResources, final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void setRawClasspath(final IClasspathEntry[] entries,
+            final IClasspathEntry[] referencedEntries, final IPath outputLocation,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public IClasspathEntry[] getReferencedClasspathEntries()
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void setRawClasspath(final IClasspathEntry[] entries,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    public void setRawClasspath(final IClasspathEntry[] entries,
+            final IPath outputLocation, final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof MockJavaProject))
+            return false;
+
+        MockJavaProject other = (MockJavaProject) o;
+        return this._project.equals(other.getProject());
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return this._project.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return super.toString().concat("[JavaProject]");
+    }
+
+}
diff --git a/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockPackageFragmentRoot.java b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockPackageFragmentRoot.java
new file mode 100644
index 0000000..aaf7be0
--- /dev/null
+++ b/jsf/tests/org.eclipse.jst.jsf.test.util/src/org/eclipse/jst/jsf/test/util/mock/java/MockPackageFragmentRoot.java
@@ -0,0 +1,207 @@
+package org.eclipse.jst.jsf.test.util.mock.java;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.IBuffer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaModelException;
+
+public class MockPackageFragmentRoot extends MockJavaElement implements
+        IPackageFragmentRoot
+{
+    public MockPackageFragmentRoot(final IJavaProject owningProject,
+            final IPath path)
+    {
+        super(owningProject, path);
+    }
+
+    @Override
+    public final int getElementType()
+    {
+        return IJavaElement.PACKAGE_FRAGMENT_ROOT;
+    }
+
+    public IJavaElement[] getChildren() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean hasChildren() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void close() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public String findRecommendedLineSeparator() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IBuffer getBuffer() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean hasUnsavedChanges() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isConsistent() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isOpen()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void makeConsistent(final IProgressMonitor progress)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void open(final IProgressMonitor progress) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void save(final IProgressMonitor progress, final boolean force)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void attachSource(final IPath sourcePath, final IPath rootPath,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void copy(final IPath destination, final int updateResourceFlags,
+            final int updateModelFlags, final IClasspathEntry sibling,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPackageFragment createPackageFragment(final String name,
+            final boolean force, final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void delete(final int updateResourceFlags,
+            final int updateModelFlags, final IProgressMonitor monitor)
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public int getKind() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object[] getNonJavaResources() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPackageFragment getPackageFragment(final String packageName)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IClasspathEntry getRawClasspathEntry() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IClasspathEntry getResolvedClasspathEntry()
+            throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPath getSourceAttachmentPath() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public IPath getSourceAttachmentRootPath() throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isArchive()
+    {
+        return "jar".equals(getPath().getFileExtension());
+    }
+
+    public boolean isExternal()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void move(final IPath destination, final int updateResourceFlags,
+            final int updateModelFlags, final IClasspathEntry sibling,
+            final IProgressMonitor monitor) throws JavaModelException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean equals(final Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+        if (!(o instanceof MockPackageFragmentRoot))
+        {
+            return false;
+        }
+        MockPackageFragmentRoot other = (MockPackageFragmentRoot) o;
+        return getPath().equals(other.getPath());
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return getPath().hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuffer buffer = new StringBuffer();
+        IPath path = getPath();
+        if (isExternal()) {
+            buffer.append(path.toOSString());
+        } else if (getJavaProject().getElementName().equals(path.segment(0))) {
+            if (path.segmentCount() == 1) {
+                buffer.append("<project root>"); //$NON-NLS-1$
+            } else {
+                buffer.append(path.removeFirstSegments(1).makeRelative());
+            }
+        } else {
+            buffer.append(path);
+        }
+//        if (info == null) {
+//            buffer.append(" (not open)"); //$NON-NLS-1$
+//        }
+        return buffer.toString();
+    }
+}