[333901] Need to update JS include path after module core nature installed
diff --git a/bundles/org.eclipse.wst.jsdt.web.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.jsdt.web.core/META-INF/MANIFEST.MF
index 95990fb..98d1bae 100644
--- a/bundles/org.eclipse.wst.jsdt.web.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.wst.jsdt.web.core/META-INF/MANIFEST.MF
@@ -23,7 +23,7 @@
 Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.filebuffers;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.wst.sse.core;bundle-version="[1.1.500,1.2.0)",
+ org.eclipse.wst.sse.core;bundle-version="[1.1.504,1.2.0)",
  org.eclipse.wst.xml.core;bundle-version="[1.1.500,1.2.0)",
  org.eclipse.wst.html.core;bundle-version="[1.1.400,1.2.0)",
  org.eclipse.wst.validation;bundle-version="[1.2.100,2.0.0)",
diff --git a/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/JSWebResourceEventManager.java b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/JSWebResourceEventManager.java
new file mode 100644
index 0000000..7d14d5d
--- /dev/null
+++ b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/JSWebResourceEventManager.java
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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.jsdt.web.core.internal;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.wst.common.componentcore.ComponentCore;
+import org.eclipse.wst.common.componentcore.ModuleCoreNature;
+import org.eclipse.wst.common.componentcore.resources.IVirtualFile;
+import org.eclipse.wst.jsdt.core.IIncludePathAttribute;
+import org.eclipse.wst.jsdt.core.IIncludePathEntry;
+import org.eclipse.wst.jsdt.core.JavaScriptCore;
+import org.eclipse.wst.jsdt.internal.core.ClasspathEntry;
+import org.eclipse.wst.jsdt.internal.core.JavaProject;
+import org.eclipse.wst.jsdt.internal.core.util.Messages;
+import org.eclipse.wst.jsdt.web.core.internal.project.ModuleSourcePathProvider;
+import org.eclipse.wst.sse.core.indexing.AbstractIndexManager;
+
+/**
+ * <p>This is an implementation of the {@link AbstractIndexManager} for the JavaScript Web core plugin.</p>
+ * 
+ * <p>Current Uses:
+ * <ul>
+ * <li>listen for .project changes so that JavaScript class paths can be updated
+ * if the module core nature is added to a project</li>
+ * </ul></p>
+ * 
+ * <p><b>NOTE:</b> If any other file resource change listening needs to take place in the future
+ * in this plugin it should be done here.</p>
+ */
+public class JSWebResourceEventManager extends AbstractIndexManager {
+	/** the singleton instance of the {@link JSWebResourceEventManager} */
+	private static JSWebResourceEventManager INSTANCE;
+	
+	/** the name of the ".project" file where natures are stored */
+	private static final String DOT_PROJECT_FILE_NAME = ".project"; //$NON-NLS-1$
+	
+	/** the location to store state */
+	private IPath fWorkingLocation;
+	
+	/**
+	 * <p>Private constructor for the resource event manager</p>
+	 */
+	private JSWebResourceEventManager() {
+		super(Messages.build_analyzingDeltas, Messages.build_analyzingDeltas,
+				Messages.javamodel_initialization, Messages.manager_filesToIndex);
+	}
+	
+	/**
+	 * @return the singleton instance of the {@link JSWebResourceEventManager}
+	 */
+	public static JSWebResourceEventManager getDefault() {
+		return INSTANCE != null ? INSTANCE : (INSTANCE = new JSWebResourceEventManager());
+	}
+
+	/**
+	 * @see org.eclipse.wst.sse.core.indexing.AbstractIndexManager#isResourceToIndex(int, org.eclipse.core.runtime.IPath)
+	 */
+	protected boolean isResourceToIndex(int type, IPath path) {
+		String name = path.lastSegment();
+		return 
+			type == IResource.ROOT ||
+			type == IResource.PROJECT || 
+			(type == IResource.FILE && name.equals(DOT_PROJECT_FILE_NAME));
+	}
+
+	/**
+	 * @see org.eclipse.wst.sse.core.indexing.AbstractIndexManager#performAction(byte, byte, org.eclipse.core.resources.IResource, org.eclipse.core.runtime.IPath)
+	 */
+	protected void performAction(byte source, byte action, IResource resource,
+			IPath movePath) {
+		
+		switch(action) {
+			case(AbstractIndexManager.ACTION_ADD): {
+				if(resource.getName().equals(DOT_PROJECT_FILE_NAME)) {
+					updateClassPathEntires(resource.getProject());
+				}
+				break;
+			}
+		}
+
+	}
+
+	/**
+	 * @see org.eclipse.wst.sse.core.indexing.AbstractIndexManager#getWorkingLocation()
+	 */
+	protected IPath getWorkingLocation() {
+		if(this.fWorkingLocation == null) {
+			//create path to working area
+    		IPath workingLocation =
+    			JsCorePlugin.getDefault().getStateLocation().append("JSWebResourceEventManager"); //$NON-NLS-1$
+
+            // ensure that it exists on disk
+            File folder = new File(workingLocation.toOSString());
+    		if (!folder.isDirectory()) {
+    			try {
+    				folder.mkdir();
+    			}
+    			catch (SecurityException e) {
+    				Logger.logException(this.getName() +
+    						": Error while creating state location: " + folder + //$NON-NLS-1$
+    						" This renders the index manager irrevocably broken for this workspace session", //$NON-NLS-1$
+    						e);
+    			}
+    		}
+    		
+    		this.fWorkingLocation = workingLocation;
+    	}
+    	
+        return this.fWorkingLocation;
+	}
+	
+	/**
+	 * <p>Updates the JavaScript class path entries for the given project if
+	 * both the Module core and JavaScript natures are installed on that project.</p>
+	 *
+	 * @param project {@link IProject} to update the JavaScript class path entires for
+	 */
+	private static void updateClassPathEntires(IProject project) {
+		try {
+			//if a JS project with Module core check if class path needs to be updated
+			if (project.hasNature(JavaScriptCore.NATURE_ID) &&
+					ModuleCoreNature.isFlexibleProject(project)) {
+				
+				JavaProject jsProject = (JavaProject) JavaScriptCore.create(project);
+				
+				IIncludePathEntry[] oldEntries = jsProject.getRawIncludepath();
+				List updatedEntries = new ArrayList();
+				boolean foundDefault = false;
+				
+				List preExistingExclusionPatterns = new ArrayList();
+				List preExistingInclusionPatterns = new ArrayList();
+				for(int oldEntry = 0; oldEntry < oldEntries.length; ++oldEntry) {
+					IIncludePathAttribute[] attrs = oldEntries[oldEntry].getExtraAttributes();
+					
+					for(int atter = 0; atter < attrs.length; ++atter) {
+						if(attrs[atter].getName().equals(ModuleSourcePathProvider.PROVIDER_ATTRIBUTE_KEY_NAME) && 
+								attrs[atter].getValue().equals(ModuleSourcePathProvider.PROVIDER_ATTRIBUTE_KEY_VALUE)) {
+							foundDefault = true;
+							
+							//create exclusion paths that are not relative to the parent entry
+							IPath[] exclusionPaths = oldEntries[oldEntry].getExclusionPatterns();
+							for(int i = 0; i < exclusionPaths.length; ++i) {
+								preExistingExclusionPatterns.add(
+										oldEntries[oldEntry].getPath().append(exclusionPaths[i]));
+							}
+							
+							//create inclusion paths that are not relative to the parent entry
+							IPath[]inclusionPaths = oldEntries[oldEntry].getInclusionPatterns();
+							for(int i = 0; i < inclusionPaths.length; ++i) {
+								preExistingInclusionPatterns.add(
+										oldEntries[oldEntry].getPath().append(inclusionPaths[i]));
+							}
+						} else {
+							updatedEntries.add(oldEntries[oldEntry]);
+						}
+					}
+					
+				}
+				
+				//if found that a default path was added, replace with module core determined path
+				if(foundDefault) {
+					IResource[] roots = getRoots(project);
+					for(int root = 0; root < roots.length; ++root) {
+						IPath rootPath = roots[root].getFullPath();
+
+						//find matching pre-existing exclusion patterns
+						List exclusionPatterns = new ArrayList();
+						for(int i = 0; i < preExistingExclusionPatterns.size(); ++i) {
+							IPath parentRelativeExclusionPattern = PathUtils.makePatternRelativeToParent(
+									(IPath)preExistingExclusionPatterns.get(i), rootPath);
+							
+							if(parentRelativeExclusionPattern != null) {
+								exclusionPatterns.add(parentRelativeExclusionPattern);
+							}
+						}
+						
+						//find matching pre-existing inclusion patterns
+						List inclusionPatterns = new ArrayList();
+						for(int i = 0; i < preExistingInclusionPatterns.size(); ++i) {
+							IPath parentRelativeInclusionPattern = PathUtils.makePatternRelativeToParent(
+									(IPath)preExistingInclusionPatterns.get(i), rootPath);
+							
+							if(parentRelativeInclusionPattern != null) {
+								inclusionPatterns.add(parentRelativeInclusionPattern);
+							}
+						}
+						
+						//create new entry entry
+						IPath[] exclusionPaths = ClasspathEntry.EXCLUDE_NONE;
+						if(exclusionPatterns.size() > 0) {
+							exclusionPaths = (IPath[])exclusionPatterns.toArray(
+									new IPath[exclusionPatterns.size()]);
+						}
+						IPath[] inclusionPaths = ClasspathEntry.INCLUDE_ALL;
+						if(inclusionPatterns.size() > 0) {
+							inclusionPaths = (IPath[])inclusionPatterns.toArray(
+									new IPath[inclusionPatterns.size()]);
+						}
+						IIncludePathEntry newEntry = JavaScriptCore.newSourceEntry(
+								rootPath,
+								inclusionPaths,
+								exclusionPaths,
+								null);
+						updatedEntries.add(newEntry);
+					}
+					
+					//set include path
+					jsProject.setRawIncludepath(
+							(IIncludePathEntry[])updatedEntries.toArray(
+									new IIncludePathEntry[updatedEntries.size()]),
+							project.getLocation(), null);
+				}
+			}
+		} catch(CoreException e) {
+			Logger.logException("Error while updating JavaScript classpath.", e); //$NON-NLS-1$
+		}
+	}
+	
+	/**
+	 * <p>Uses module core to get the roots of the given project.</p>
+	 *
+	 * @param project find the module core roots for this {@link IProject}
+	 * @return the module core roots for the given {@link IProject
+	 */
+	private static IResource[] getRoots(IProject project) {
+		IVirtualFile root = ComponentCore.createFile(project, Path.ROOT);
+		IResource[] underlyingResources = root.getUnderlyingResources();
+		if (underlyingResources == null || underlyingResources.length == 0) {
+			underlyingResources = new IResource[]{root.getUnderlyingResource()};
+		}
+		
+		return underlyingResources;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/JsCorePlugin.java b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/JsCorePlugin.java
index ef6801a..7c99760 100644
--- a/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/JsCorePlugin.java
+++ b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/JsCorePlugin.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2008 IBM Corporation and others.
+ * Copyright (c) 2004, 2011 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
@@ -10,7 +10,21 @@
  *******************************************************************************/
 package org.eclipse.wst.jsdt.web.core.internal;
 
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.ISaveContext;
+import org.eclipse.core.resources.ISaveParticipant;
+import org.eclipse.core.resources.ISavedState;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.wst.jsdt.internal.core.util.Messages;
 import org.eclipse.wst.jsdt.web.core.javascript.search.JsIndexManager;
 import org.osgi.framework.BundleContext;
 
@@ -27,12 +41,14 @@
 	public static final String PLUGIN_ID = "org.eclipse.wst.jsdt.web.core"; //$NON-NLS-1$
 	
 	/**
-	 * Returns the shared instance.
-	 * 
-	 * @deprecated - will be removed. Currently used to get "model preferences",
-	 *             but there are other, better ways.
+	 * <p>Job used to finish tasks needed to start up the plugin but that did not have
+	 * to block the plugin start up process.</p>
 	 */
-
+	private Job fPluginInitializerJob;
+	
+	/**
+	 * Returns the shared instance.
+	 */
 	public static JsCorePlugin getDefault() {
 		return JsCorePlugin.plugin;
 	}
@@ -43,6 +59,7 @@
 	public JsCorePlugin() {
 		super();
 		JsCorePlugin.plugin = this;
+		this.fPluginInitializerJob = new PluginInitializerJob();
 	}
 	
 	/*
@@ -58,6 +75,10 @@
 		// listen for classpath changes
 		JsIndexManager.getInstance().initialize();
 		// listen for resource changes to update content properties keys
+		
+		//schedule delayed initialization
+		this.fPluginInitializerJob.schedule(2000);
+
 	}
 	
 	/*
@@ -71,6 +92,123 @@
 		// keys
 		// stop any indexing
 		JsIndexManager.getInstance().shutdown();
+		
+		//Stop the resource event manager
+		JSWebResourceEventManager.getDefault().stop();
+		
 		super.stop(context);
 	}
+	
+	/**
+	 * <p>A {@link Job} used to perform delayed initialization for the plugin</p>
+	 */
+	private static class PluginInitializerJob extends Job {
+		/**
+		 * <p>Default constructor to set up this {@link Job} as a
+		 * long running system {@link Job}</p>
+		 */
+		protected PluginInitializerJob() {
+			super(Messages.javamodel_initialization);
+			
+			this.setUser(false);
+			this.setSystem(true);
+			this.setPriority(Job.LONG);
+		}
+		
+		/**
+		 * <p>Perform delayed initialization for the plugin</p>
+		 * 
+		 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+		 */
+		protected IStatus run(IProgressMonitor monitor) {
+			IStatus status = Status.OK_STATUS;
+			final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+			try {
+				/*
+				 * Restore save state and process any events that happened before
+				 * plug-in loaded. Don't do it immediately since adding the save
+				 * participant requires a lock on the workspace to compute the
+				 * accumulated deltas, and if the tree is not already locked it
+				 * becomes a blocking call.
+				 */
+				workspace.run(new IWorkspaceRunnable() {
+					public void run(final IProgressMonitor worspaceMonitor) throws CoreException {
+						ISavedState savedState = null;
+						
+						try {
+							//add the save participant for this bundle
+							savedState = ResourcesPlugin.getWorkspace().addSaveParticipant(
+									JsCorePlugin.plugin.getBundle().getSymbolicName(), new SaveParticipant());
+						} catch (CoreException e) {
+							Logger.logException("JSP Core Plugin failed at loading previously saved state." + //$NON-NLS-1$
+									" All componenets dependent on this state will start as if first workspace load.", e); //$NON-NLS-1$
+						}
+						
+						//if there is a saved state start up using that, else start up cold
+						if(savedState != null) {
+							try {
+								Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
+							} finally {
+								savedState.processResourceChangeEvents(new IResourceChangeListener() {
+									/**
+									 * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
+									 */
+									public void resourceChanged(IResourceChangeEvent event) {
+										JSWebResourceEventManager.getDefault().start(event.getDelta(), worspaceMonitor);
+									}
+								});
+							}
+						} else {
+							JSWebResourceEventManager.getDefault().start(null, worspaceMonitor);
+						}
+					}
+				}, monitor);
+			} catch(CoreException e) {
+				status = e.getStatus();
+			}
+			
+			return status;
+		}
+		
+	}
+	
+	/**
+	 * Used so that all of the IResourceChangeEvents that occurred before
+	 * this plugin loaded can be processed.
+	 */
+	private static class SaveParticipant implements ISaveParticipant {
+		/**
+		 * <p>Default constructor</p>
+		 */
+		protected SaveParticipant() {
+		}
+		
+		/**
+		 * @see org.eclipse.core.resources.ISaveParticipant#doneSaving(org.eclipse.core.resources.ISaveContext)
+		 */
+		public void doneSaving(ISaveContext context) {
+			//ignore
+		}
+	
+		/**
+		 * @see org.eclipse.core.resources.ISaveParticipant#prepareToSave(org.eclipse.core.resources.ISaveContext)
+		 */
+		public void prepareToSave(ISaveContext context) throws CoreException {
+			//ignore
+		}
+	
+		/**
+		 * @see org.eclipse.core.resources.ISaveParticipant#rollback(org.eclipse.core.resources.ISaveContext)
+		 */
+		public void rollback(ISaveContext context) {
+			//ignore
+		}
+	
+		/**
+		 * @see org.eclipse.core.resources.ISaveParticipant#saving(org.eclipse.core.resources.ISaveContext)
+		 */
+		public void saving(ISaveContext context) throws CoreException {
+			context.needDelta();
+		}
+	}
 }
diff --git a/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/PathUtils.java b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/PathUtils.java
new file mode 100644
index 0000000..5d8670e
--- /dev/null
+++ b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/PathUtils.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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.jsdt.web.core.internal;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.wst.jsdt.core.compiler.CharOperation;
+
+/**
+ * <p>Utility class dealing with {@link IPath}s.</p>
+ */
+public class PathUtils {
+	/** represents the * pattern in a path pattern */
+	private static final String STAR = "*"; //$NON-NLS-1$
+	
+	/** represents the ** pattern in a path pattern */
+	private static final String STAR_STAR = "**"; //$NON-NLS-1$
+	
+	/**
+	 * <p>Counts the number of segments in a given pattern that match segments in a given parent path.
+	 * This counting takes place from the beginning of both the pattern and parent and stops when
+	 * they no longer match.  The pattern can contain **, * and ? wild cards.</p>
+	 *
+	 * @param pattern count the number of segments of this pattern that match the given <code>parent</code>
+	 * @param parent count the number of segments in the given <code>pattern</code> that match this path
+	 * @return the number of segments from the beginning of the given <code>pattern</code> {@link IPath}
+	 * that match the beginning segments of the given <code>parent</code> {@link IPath}
+	 */
+	public static int countPatternSegmentsThatMatchParent(IPath pattern, IPath parent) {
+		int matchingSegments = 0;
+		
+		//ignore a pattern that is just ** or *
+		if(!(pattern.segmentCount() == 1 &&
+				(pattern.segment(0).equals(STAR_STAR) || pattern.segment(0).equals(STAR)))) {
+			
+			int patternSegmentIndex = 0;
+			int parentSegmentIndex = 0;
+			boolean starStarMode = false;
+			while(patternSegmentIndex < pattern.segmentCount() &&
+					parentSegmentIndex < parent.segmentCount()) {
+				
+				String patternSegment = pattern.segment(patternSegmentIndex);
+				String parentSegment = parent.segment(parentSegmentIndex);
+				
+				/* if matching on wild
+				 * else if wild match on multiple path segments
+				 * else if wild match on one path segment or path segments are equal
+				 * else not equal so stop comparing
+				 */
+				if(starStarMode) {
+					/* if parent segment equals first pattern segment after a ** stop matching on it
+					 * else still matching on **
+					 */
+					if(pathSegmentMatchesPattern(patternSegment, parentSegment)) {
+						starStarMode = false;
+						matchingSegments++;
+						patternSegmentIndex++;
+						parentSegmentIndex++;
+					} else {
+						parentSegmentIndex++;
+					}
+				
+				} else if(patternSegment.equals(STAR_STAR)) { //$NON-NLS-1$
+					starStarMode = true;
+					
+					//find the first pattern segment after the ** that is not another ** or *
+					matchingSegments++;
+					parentSegmentIndex++;
+					
+					for(int i = patternSegmentIndex+1; i < pattern.segmentCount(); ++i) {
+						
+						if(!(pattern.segment(i).equals(STAR_STAR) || //$NON-NLS-1$
+								pattern.segment(i).equals(STAR))) { //$NON-NLS-1$
+							
+							patternSegmentIndex = i;
+							break;
+						}
+					}
+				} else if(patternSegment.equals("*") || //$NON-NLS-1$
+						pathSegmentMatchesPattern(patternSegment, parentSegment)){
+					
+					matchingSegments++;
+					patternSegmentIndex++;
+					parentSegmentIndex++;
+				} else {
+					break;
+				}
+			}
+		}
+		
+		return matchingSegments;
+	}
+	
+	/**
+	 * <p>Given a pattern path and a parent path attempts to truncate the given pattern path such
+	 * that it is relative to the given parent path.</p>
+	 *
+	 * @param pattern attempt to truncate this {@link IPath} such that it is relative to the given
+	 * <code>parent</code> {@link IPath}
+	 * @param parent attempt to truncate the given <code>pattern</code> {@link IPath} such that it
+	 * is relative to this {@link IPath}
+	 * @return either a truncated version of the given <code>pattern</code> {@link IPath} that is
+	 * relative to the given <code>parent</code> {@link IPath}, or <code>null</code> if the given
+	 * <code>pattern</code> {@link IPath} could not be truncated to be relative to the given
+	 * <code>parent</code> {@link IPath}
+	 */
+	public static IPath makePatternRelativeToParent(IPath pattern, IPath parent) {
+		int matchedSegments = countPatternSegmentsThatMatchParent(pattern, parent);
+		
+		IPath relativePattern = null;
+		if(matchedSegments != 0) {
+			relativePattern = pattern.removeFirstSegments(matchedSegments);
+			
+			if(relativePattern.segmentCount() == 0) {
+				relativePattern = null;
+			} else {
+				relativePattern.makeRelative();
+			}
+		}
+		
+		return relativePattern;
+	}
+	
+	/**
+	 * <p>A convenience method for checking the matching of one segment from a pattern path with
+	 * one segment from a path.</p>
+	 *Bug 334922 - CharOperation#match does not work as expected when isCaseSensitive is passed as false
+	 * @param patternSegment check if this pattern segment is a match with the given path segment.
+	 * @param segment check if this path segment matches with the given pattern segment
+	 * @return <code>true</code> if the segments match, <code>false</code> otherwise
+	 */
+	private static boolean pathSegmentMatchesPattern(String patternSegment, String segment) {
+		return CharOperation.pathMatch(patternSegment.toCharArray(), segment.toCharArray(),
+				false, File.separatorChar);
+	}
+}
diff --git a/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/project/ModuleSourcePathProvider.java b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/project/ModuleSourcePathProvider.java
index 3a98b89..1183854 100644
--- a/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/project/ModuleSourcePathProvider.java
+++ b/bundles/org.eclipse.wst.jsdt.web.core/src/org/eclipse/wst/jsdt/web/core/internal/project/ModuleSourcePathProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2010 IBM Corporation and others.

+ * Copyright (c) 2010, 2011 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

@@ -17,12 +17,17 @@
 import org.eclipse.wst.common.componentcore.ComponentCore;

 import org.eclipse.wst.common.componentcore.ModuleCoreNature;

 import org.eclipse.wst.common.componentcore.resources.IVirtualFile;

+import org.eclipse.wst.jsdt.core.IIncludePathAttribute;

 import org.eclipse.wst.jsdt.core.IIncludePathEntry;

 import org.eclipse.wst.jsdt.core.JavaScriptCore;

+import org.eclipse.wst.jsdt.internal.core.ClasspathEntry;

 import org.eclipse.wst.jsdt.internal.core.util.DefaultSourcePathProvider;

 

 public class ModuleSourcePathProvider extends DefaultSourcePathProvider {

 

+	public static final String PROVIDER_ATTRIBUTE_KEY_NAME = "provider"; //$NON-NLS-1$

+	public static final String PROVIDER_ATTRIBUTE_KEY_VALUE = ModuleSourcePathProvider.class.getName(); //$NON-NLS-1$

+	

 	public ModuleSourcePathProvider() {

 	}

 

@@ -47,6 +52,9 @@
 				}

 			}

 		}

-		return super.getDefaultSourcePaths(p);

+		

+		return new IIncludePathEntry[]{JavaScriptCore.newSourceEntry(p.getFullPath(),

+				ClasspathEntry.INCLUDE_ALL,ClasspathEntry.EXCLUDE_NONE,null,

+				new IIncludePathAttribute[]{JavaScriptCore.newIncludepathAttribute(PROVIDER_ATTRIBUTE_KEY_NAME, PROVIDER_ATTRIBUTE_KEY_VALUE)})};

 	}

 }