This commit was manufactured by cvs2svn to create branch 'R3_0_4_patches'.
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/.cvsignore b/features/org.eclipse.wst.common_ui.feature.patch/.cvsignore
new file mode 100644
index 0000000..c14487c
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/.cvsignore
@@ -0,0 +1 @@
+build.xml
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/.project b/features/org.eclipse.wst.common_ui.feature.patch/.project
new file mode 100644
index 0000000..0dbb12b
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.wst.common_ui.feature.patch</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/build.properties b/features/org.eclipse.wst.common_ui.feature.patch/build.properties
new file mode 100644
index 0000000..cb50260
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/build.properties
@@ -0,0 +1,5 @@
+bin.includes = feature.xml,\
+               license.html,\
+               feature.properties,\
+               epl-v10.html,\
+               eclipse_update_120.jpg
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/buildnotes_org.eclipse.wst.common_ui.feature.patch.html b/features/org.eclipse.wst.common_ui.feature.patch/buildnotes_org.eclipse.wst.common_ui.feature.patch.html
new file mode 100644
index 0000000..595ca3c
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/buildnotes_org.eclipse.wst.common_ui.feature.patch.html
@@ -0,0 +1,20 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Build" content="Build">
+<title>WTP 1.5.5 Patches</title>
+</head>
+
+<body>
+
+<h1>WTP 1.5.5 Patches</h1>
+
+<h2>org.eclipse.wst.common_ui.feature</h2>
+
+<p>Bug <a
+	href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=245433">245433</a>
+IValidateEditListener should be used when changing target runtime</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/eclipse_update_120.jpg b/features/org.eclipse.wst.common_ui.feature.patch/eclipse_update_120.jpg
new file mode 100644
index 0000000..bfdf708
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/eclipse_update_120.jpg
Binary files differ
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/epl-v10.html b/features/org.eclipse.wst.common_ui.feature.patch/epl-v10.html
new file mode 100644
index 0000000..ed4b196
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/epl-v10.html
@@ -0,0 +1,328 @@
+<html xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:w="urn:schemas-microsoft-com:office:word"
+xmlns="http://www.w3.org/TR/REC-html40">
+
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+<meta name=ProgId content=Word.Document>
+<meta name=Generator content="Microsoft Word 9">
+<meta name=Originator content="Microsoft Word 9">
+<link rel=File-List
+href="./Eclipse%20EPL%202003_11_10%20Final_files/filelist.xml">
+<title>Eclipse Public License - Version 1.0</title>
+<!--[if gte mso 9]><xml>
+ <o:DocumentProperties>
+  <o:Revision>2</o:Revision>
+  <o:TotalTime>3</o:TotalTime>
+  <o:Created>2004-03-05T23:03:00Z</o:Created>
+  <o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
+  <o:Pages>4</o:Pages>
+  <o:Words>1626</o:Words>
+  <o:Characters>9270</o:Characters>
+   <o:Lines>77</o:Lines>
+  <o:Paragraphs>18</o:Paragraphs>
+  <o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
+  <o:Version>9.4402</o:Version>
+ </o:DocumentProperties>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <w:WordDocument>
+  <w:TrackRevisions/>
+ </w:WordDocument>
+</xml><![endif]-->
+<style>
+<!--
+ /* Font Definitions */
+@font-face
+	{font-family:Tahoma;
+	panose-1:2 11 6 4 3 5 4 4 2 4;
+	mso-font-charset:0;
+	mso-generic-font-family:swiss;
+	mso-font-pitch:variable;
+	mso-font-signature:553679495 -2147483648 8 0 66047 0;}
+ /* Style Definitions */
+p.MsoNormal, li.MsoNormal, div.MsoNormal
+	{mso-style-parent:"";
+	margin:0in;
+	margin-bottom:.0001pt;
+	mso-pagination:widow-orphan;
+	font-size:12.0pt;
+	font-family:"Times New Roman";
+	mso-fareast-font-family:"Times New Roman";}
+p
+	{margin-right:0in;
+	mso-margin-top-alt:auto;
+	mso-margin-bottom-alt:auto;
+	margin-left:0in;
+	mso-pagination:widow-orphan;
+	font-size:12.0pt;
+	font-family:"Times New Roman";
+	mso-fareast-font-family:"Times New Roman";}
+p.BalloonText, li.BalloonText, div.BalloonText
+	{mso-style-name:"Balloon Text";
+	margin:0in;
+	margin-bottom:.0001pt;
+	mso-pagination:widow-orphan;
+	font-size:8.0pt;
+	font-family:Tahoma;
+	mso-fareast-font-family:"Times New Roman";}
+@page Section1
+	{size:8.5in 11.0in;
+	margin:1.0in 1.25in 1.0in 1.25in;
+	mso-header-margin:.5in;
+	mso-footer-margin:.5in;
+	mso-paper-source:0;}
+div.Section1
+	{page:Section1;}
+-->
+</style>
+</head>
+
+<body lang=EN-US style='tab-interval:.5in'>
+
+<div class=Section1>
+
+<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
+</p>
+
+<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
+THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
+REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
+OF THIS AGREEMENT.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+in the case of the initial Contributor, the initial code and documentation
+distributed under this Agreement, and<br clear=left>
+b) in the case of each subsequent Contributor:</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
+changes to the Program, and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
+additions to the Program;</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
+such changes and/or additions to the Program originate from and are distributed
+by that particular Contributor. A Contribution 'originates' from a Contributor
+if it was added to the Program by such Contributor itself or anyone acting on
+such Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in conjunction
+with the Program under their own license agreement, and (ii) are not derivative
+works of the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
+entity that distributes the Program.</span> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
+claims licensable by a Contributor which are necessarily infringed by the use
+or sale of its Contribution alone or when combined with the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
+distributed in accordance with this Agreement.</span> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
+receives the Program under this Agreement, including all Contributors.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+Subject to the terms of this Agreement, each Contributor hereby grants Recipient
+a non-exclusive, worldwide, royalty-free copyright license to<span
+style='color:red'> </span>reproduce, prepare derivative works of, publicly
+display, publicly perform, distribute and sublicense the Contribution of such
+Contributor, if any, and such derivative works, in source code and object code
+form.</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
+Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
+patent license under Licensed Patents to make, use, sell, offer to sell, import
+and otherwise transfer the Contribution of such Contributor, if any, in source
+code and object code form. This patent license shall apply to the combination
+of the Contribution and the Program if, at the time the Contribution is added
+by the Contributor, such addition of the Contribution causes such combination
+to be covered by the Licensed Patents. The patent license shall not apply to
+any other combinations which include the Contribution. No hardware per se is
+licensed hereunder. </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
+Recipient understands that although each Contributor grants the licenses to its
+Contributions set forth herein, no assurances are provided by any Contributor
+that the Program does not infringe the patent or other intellectual property
+rights of any other entity. Each Contributor disclaims any liability to Recipient
+for claims brought by any other entity based on infringement of intellectual
+property rights or otherwise. As a condition to exercising the rights and
+licenses granted hereunder, each Recipient hereby assumes sole responsibility
+to secure any other intellectual property rights needed, if any. For example,
+if a third party patent license is required to allow Recipient to distribute
+the Program, it is Recipient's responsibility to acquire that license before
+distributing the Program.</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
+Each Contributor represents that to its knowledge it has sufficient copyright
+rights in its Contribution, if any, to grant the copyright license set forth in
+this Agreement. </span></p>
+
+<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
+
+<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
+Program in object code form under its own license agreement, provided that:</span>
+</p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+it complies with the terms and conditions of this Agreement; and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
+its license agreement:</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
+effectively disclaims on behalf of all Contributors all warranties and
+conditions, express and implied, including warranties or conditions of title
+and non-infringement, and implied warranties or conditions of merchantability
+and fitness for a particular purpose; </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
+effectively excludes on behalf of all Contributors all liability for damages,
+including direct, indirect, special, incidental and consequential damages, such
+as lost profits; </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
+states that any provisions which differ from this Agreement are offered by that
+Contributor alone and not by any other party; and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
+states that source code for the Program is available from such Contributor, and
+informs licensees how to obtain it in a reasonable manner on or through a
+medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
+
+<p><span style='font-size:10.0pt'>When the Program is made available in source
+code form:</span> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+it must be made available under this Agreement; and </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
+copy of this Agreement must be included with each copy of the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
+copyright notices contained within the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
+originator of its Contribution, if any, in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution. </span></p>
+
+<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
+
+<p><span style='font-size:10.0pt'>Commercial distributors of software may
+accept certain responsibilities with respect to end users, business partners
+and the like. While this license is intended to facilitate the commercial use
+of the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes the
+Program in a commercial product offering, such Contributor (&quot;Commercial
+Contributor&quot;) hereby agrees to defend and indemnify every other
+Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
+costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
+legal actions brought by a third party against the Indemnified Contributor to
+the extent caused by the acts or omissions of such Commercial Contributor in
+connection with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In order
+to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor
+to control, and cooperate with the Commercial Contributor in, the defense and
+any related settlement negotiations. The Indemnified Contributor may participate
+in any such claim at its own expense.</span> </p>
+
+<p><span style='font-size:10.0pt'>For example, a Contributor might include the
+Program in a commercial product offering, Product X. That Contributor is then a
+Commercial Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance claims and
+warranties are such Commercial Contributor's responsibility alone. Under this
+section, the Commercial Contributor would have to defend claims against the
+other Contributors related to those performance claims and warranties, and if a
+court requires any other Contributor to pay any damages as a result, the
+Commercial Contributor must pay those damages.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
+
+<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
+AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
+WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and distributing the
+Program and assumes all risks associated with its exercise of rights under this
+Agreement , including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs or
+equipment, and unavailability or interruption of operations. </span></p>
+
+<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
+
+<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
+AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
+THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
+
+<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
+or unenforceable under applicable law, it shall not affect the validity or
+enforceability of the remainder of the terms of this Agreement, and without
+further action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.</span> </p>
+
+<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
+against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with
+other software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the date
+such litigation is filed. </span></p>
+
+<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
+shall terminate if it fails to comply with any of the material terms or
+conditions of this Agreement and does not cure such failure in a reasonable
+period of time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive. </span></p>
+
+<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
+copies of this Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The Agreement
+Steward reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement Steward has
+the right to modify this Agreement. The Eclipse Foundation is the initial
+Agreement Steward. The Eclipse Foundation may assign the responsibility to
+serve as the Agreement Steward to a suitable separate entity. Each new version
+of the Agreement will be given a distinguishing version number. The Program
+(including Contributions) may always be distributed subject to the version of
+the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly stated
+in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether
+expressly, by implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.</span> </p>
+
+<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
+State of New York and the intellectual property laws of the United States of
+America. No party to this Agreement will bring a legal action under this
+Agreement more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.</span> </p>
+
+<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
+
+</div>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/feature.properties b/features/org.eclipse.wst.common_ui.feature.patch/feature.properties
new file mode 100644
index 0000000..f9e7e53
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/feature.properties
@@ -0,0 +1,148 @@
+###############################################################################
+# Copyright (c) 2008 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+# 
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+# feature.properties
+# contains externalized strings for feature.xml
+# "%foo" in feature.xml corresponds to the key "foo" in this file
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file should be translated.
+
+# "featureName" property - name of the feature
+featureName=WTP Patches for org.eclipse.wst.common_ui.feature
+
+# "providerName" property - name of the company that provides the feature
+providerName=Eclipse.org
+
+# "updateSiteName" property - label for the update site
+updateSiteName=The Eclipse Web Tools Platform (WTP) Project update site
+
+# "description" property - description of the feature
+description=\
+Contains fixes described in the following bugillia(s):\n\
+\n\
+Bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=245433 IValidateEditListener should be used when changing target runtime\n\
+\n\
+
+# "copyright" property - text of the "Feature Update Copyright"
+copyright=\
+Copyright (c) 2008 IBM Corporation and others.\n\
+All rights reserved. This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Public License v1.0\n\
+which accompanies this distribution, and is available at\n\
+http://www.eclipse.org/legal/epl-v10.html\n\
+\n\
+Contributors:\n\
+    IBM Corporation - initial API and implementation\n
+################ end of copyright property ####################################
+
+# "licenseURL" property - URL of the "Feature License"
+# do not translate value - just change to point to a locale-specific HTML page
+licenseURL=license.html
+
+# "license" property - text of the "Feature Update License"
+# should be plain text version of license agreement pointed to be "licenseURL"
+license=\
+ECLIPSE FOUNDATION SOFTWARE USER AGREEMENT\n\
+September, 2008\n\
+\n\
+Usage Of Content\n\
+\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
+OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
+USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
+AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
+NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU\n\
+AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
+AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
+OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+\n\
+Applicable Licenses\n\
+\n\
+Unless otherwise indicated, all Content made available by the Eclipse Foundation\n\
+is provided to you under the terms and conditions of the Eclipse Public\n\
+License Version 1.0 ("EPL"). A copy of the EPL is provided with this\n\
+Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
+For purposes of the EPL, "Program" will mean the Content.\n\
+\n\
+Content includes, but is not limited to, source code, object code,\n\
+documentation and other files maintained in the Eclipse.org CVS\n\
+repository ("Repository") in CVS modules ("Modules") and made available\n\
+as downloadable archives ("Downloads").\n\
+\n\
+   - Content may be structured and packaged into modules to facilitate delivering,\n\
+     extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
+     plug-in fragments ("Fragments"), and features ("Features").\n\
+   - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java? ARchive)\n\
+     in a directory named "plugins".\n\
+   - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
+     Each Feature may be packaged as a sub-directory in a directory named "features".\n\
+     Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
+     numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
+   - Features may also include other Features ("Included Features"). Within a Feature, files\n\
+     named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+\n\
+Features may also include other Features ("Included Features"). Files named\n\
+"feature.xml" may contain a list of the names and version numbers of\n\
+Included Features.\n\
+\n\
+The terms and conditions governing Plug-ins and Fragments should be\n\
+contained in files named "about.html" ("Abouts"). The terms and\n\
+conditions governing Features and Included Features should be contained\n\
+in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
+Licenses may be located in any directory of a Download or Module\n\
+including, but not limited to the following locations:\n\
+\n\
+   - The top-level (root) directory\n\
+   - Plug-in and Fragment directories\n\
+   - Inside Plug-ins and Fragments packaged as JARs\n\
+   - Sub-directories of the directory named "src" of certain Plug-ins\n\
+   - Feature directories\n\
+\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
+Eclipse Update Manager, you must agree to a license ("Feature Update\n\
+License") during the installation process. If the Feature contains\n\
+Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform\n\
+you where you can locate them. Feature Update Licenses may be found in\n\
+the "license" property of files named "feature.properties". Such Abouts,\n\
+Feature Licenses and Feature Update Licenses contain the terms and\n\
+conditions (or references to such terms and conditions) that govern your\n\
+use of the associated Content in that directory.\n\
+\n\
+THE ABOUTS, FEATURE LICENSES AND FEATURE UPDATE LICENSES MAY REFER\n\
+TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
+SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+\n\
+    - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
+    - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
+    - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
+    - IBM Public License 1.0 (available at http://oss.software.ibm.com/developerworks/opensource/license10.html)\n\
+    - Metro Link Public License 1.00 (available at http://www.opengroup.org/openmotif/supporters/metrolink/license.html)\n\
+    - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
+TO USE OF THE CONTENT. If no About, Feature License or Feature Update License\n\
+is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
+govern that particular Content.\n\
+\n\
+Cryptography\n\
+\n\
+Content may contain encryption software. The country in which you are\n\
+currently may have restrictions on the import, possession, and use,\n\
+and/or re-export to another country, of encryption software. BEFORE\n\
+using any encryption software, please check the country's laws,\n\
+regulations and policies concerning the import, possession, or use,\n\
+and re-export of encryption software, to see if this is permitted.\n\
+\n\
+Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/feature.xml b/features/org.eclipse.wst.common_ui.feature.patch/feature.xml
new file mode 100644
index 0000000..69215b9
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/feature.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.eclipse.wst.common_ui.feature.patch"
+      label="%featureName"
+      version="1.5.5.qualifier"
+      provider-name="%providerName">
+
+   <description>
+      %description
+   </description>
+
+   <copyright>
+      %copyright
+   </copyright>
+
+   <license url="%licenseURL">
+      %license
+   </license>
+
+   <requires>
+      <import feature="org.eclipse.wst.common_ui.feature" version="1.5.5.v200707311635-qKHiZIRPOkpEay9" patch="true"/>
+   </requires>
+
+   <plugin
+         id="org.eclipse.wst.common.project.facet.ui"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/features/org.eclipse.wst.common_ui.feature.patch/license.html b/features/org.eclipse.wst.common_ui.feature.patch/license.html
new file mode 100644
index 0000000..2347060
--- /dev/null
+++ b/features/org.eclipse.wst.common_ui.feature.patch/license.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
+<!-- saved from url=(0044)http://www.eclipse.org/legal/epl/notice.html -->
+<HTML><HEAD><TITLE>Eclipse.org Software User Agreement</TITLE>
+<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
+<META content="MSHTML 6.00.2800.1479" name=GENERATOR></HEAD>
+<BODY lang=EN-US vLink=purple link=blue>
+<H2>Eclipse Foundation Software User Agreement</H2>
+<P>January 28, 2005</P>
+<H3>Usage Of Content</H3>
+<P>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION 
+AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF 
+THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE 
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED 
+BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED 
+BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE 
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE 
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY 
+APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU 
+MAY NOT USE THE CONTENT.</P>
+<H3>Applicable Licenses</H3>
+<P>Unless otherwise indicated, all Content made available by the Eclipse 
+Foundation is provided to you under the terms and conditions of the Eclipse 
+Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this 
+Content and is also available at <A 
+href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</A>. 
+For purposes of the EPL, "Program" will mean the Content.</P>
+<P>Content includes, but is not limited to, source code, object code, 
+documentation and other files maintained in the Eclipse.org CVS repository 
+("Repository") in CVS modules ("Modules") and made available as downloadable 
+archives ("Downloads").</P>
+<P>Content may be apportioned into plug-ins ("Plug-ins"), plug-in fragments 
+("Fragments"), and features ("Features"). A Feature is a bundle of one or more 
+Plug-ins and/or Fragments and associated material. Files named "feature.xml" may 
+contain a list of the names and version numbers of the Plug-ins and/or Fragments 
+associated with a Feature. Plug-ins and Fragments are located in directories 
+named "plugins" and Features are located in directories named "features".</P>
+<P>Features may also include other Features ("Included Features"). Files named 
+"feature.xml" may contain a list of the names and version numbers of Included 
+Features.</P>
+<P>The terms and conditions governing Plug-ins and Fragments should be contained 
+in files named "about.html" ("Abouts"). The terms and conditions governing 
+Features and Included Features should be contained in files named "license.html" 
+("Feature Licenses"). Abouts and Feature Licenses may be located in any 
+directory of a Download or Module including, but not limited to the following 
+locations:</P>
+<UL>
+  <LI>The top-level (root) directory 
+  <LI>Plug-in and Fragment directories 
+  <LI>Subdirectories of the directory named "src" of certain Plug-ins 
+  <LI>Feature directories </LI></UL>
+<P>Note: if a Feature made available by the Eclipse Foundation is installed 
+using the Eclipse Update Manager, you must agree to a license ("Feature Update 
+License") during the installation process. If the Feature contains Included 
+Features, the Feature Update License should either provide you with the terms 
+and conditions governing the Included Features or inform you where you can 
+locate them. Feature Update Licenses may be found in the "license" property of 
+files named "feature.properties". Such Abouts, Feature Licenses and Feature 
+Update Licenses contain the terms and conditions (or references to such terms 
+and conditions) that govern your use of the associated Content in that 
+directory.</P>
+<P>THE ABOUTS, FEATURE LICENSES AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL 
+OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE 
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</P>
+<UL>
+  <LI>Common Public License Version 1.0 (available at <A 
+  href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</A>) 
+
+  <LI>Apache Software License 1.1 (available at <A 
+  href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</A>) 
+
+  <LI>Apache Software License 2.0 (available at <A 
+  href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</A>) 
+
+  <LI>IBM Public License 1.0 (available at <A 
+  href="http://oss.software.ibm.com/developerworks/opensource/license10.html">http://oss.software.ibm.com/developerworks/opensource/license10.html</A>) 
+
+  <LI>Metro Link Public License 1.00 (available at <A 
+  href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</A>) 
+
+  <LI>Mozilla Public License Version 1.1 (available at <A 
+  href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</A>) 
+  </LI></UL>
+<P>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR 
+TO USE OF THE CONTENT. If no About, Feature License or Feature Update License is 
+provided, please contact the Eclipse Foundation to determine what terms and 
+conditions govern that particular Content.</P>
+<H3>Cryptography</H3>
+<P>Content may contain encryption software. The country in which you are 
+currently may have restrictions on the import, possession, and use, and/or 
+re-export to another country, of encryption software. BEFORE using any 
+encryption software, please check the country's laws, regulations and policies 
+concerning the import, possession, or use, and re-export of encryption software, 
+to see if this is permitted.</P></BODY></HTML>
diff --git a/plugins/org.eclipse.wst.common.modulecore/META-INF/MANIFEST.MF b/plugins/org.eclipse.wst.common.modulecore/META-INF/MANIFEST.MF
index ff21c5b..b4bf115 100644
--- a/plugins/org.eclipse.wst.common.modulecore/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.wst.common.modulecore/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %Bundle-Name.0
 Bundle-Vendor: %provider
 Bundle-SymbolicName: org.eclipse.wst.common.modulecore; singleton:=true
-Bundle-Version: 1.1.202.qualifier
+Bundle-Version: 1.1.205.qualifier
 Bundle-Activator: org.eclipse.wst.common.componentcore.internal.ModulecorePlugin
 Bundle-Localization: plugin
 Export-Package: org.eclipse.wst.common.componentcore,
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ArtifactEdit.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ArtifactEdit.java
index 46c541d..77cca57 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ArtifactEdit.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ArtifactEdit.java
@@ -281,13 +281,22 @@
 	 *            {@see ModuleCoreNature}
 	 */
 	protected ArtifactEdit(ModuleCoreNature aNature, IVirtualComponent aModule, boolean toAccessAsReadOnly) {
-		if (toAccessAsReadOnly)
-			artifactEditModel = aNature.getArtifactEditModelForRead(ModuleURIUtil.fullyQualifyURI(aModule.getProject()), this);
-		else
-			artifactEditModel = aNature.getArtifactEditModelForWrite(ModuleURIUtil.fullyQualifyURI(aModule.getProject()), this);
+		
 		isReadOnly = toAccessAsReadOnly;
 		isArtifactEditModelSelfManaged = true;
 		project = aNature.getProject();
+		IProject aProject = aModule.getProject();
+		URI componentURI = ModuleURIUtil.fullyQualifyURI(aProject);
+		Map editModelParams = null;
+		if (getContentTypeDescriber() != null) {
+			editModelParams = new HashMap();
+			editModelParams.put(ArtifactEditModelFactory.PARAM_ROOT_URI, getRootURI());
+			editModelParams.put(ArtifactEditModelFactory.PARAM_ROOT_CONTENT_TYPE, getContentTypeDescriber());
+		}
+		if (toAccessAsReadOnly) 
+			artifactEditModel = aNature.getArtifactEditModelForRead(componentURI, this, null, editModelParams);
+		else 
+			artifactEditModel = aNature.getArtifactEditModelForWrite(componentURI, this, null, editModelParams);
 	}
 
 	/**
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ComponentCore.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ComponentCore.java
index 93c1e35..062a5e5 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ComponentCore.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ComponentCore.java
@@ -70,6 +70,26 @@
 	 * 
 	 * @param aProject
 	 *            A valid, accessible project to contain the component
+	 * @param checkForComponentFile
+	 *            A flag to indicate if the presence of the component file should be checked
+	 * @return A handle to an IVirtualComponent that may or may not exist or
+	 *         null if passed project does not contain ModuleCoreNature.
+	 * @see org.eclipse.core.runtime.IProgressMonitor#create(int, org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	public static IVirtualComponent createComponent(IProject aProject, boolean checkForComponentFile) {
+		if (aProject == null || !aProject.isAccessible()){
+			return null;
+		}
+		return ComponentImplManager.instance().createComponent(aProject, checkForComponentFile);
+	}
+
+	/**
+	 * Return an IVirtualComponent with the given name (aComponentName)
+	 * contained by the given project (aProject). Component names should be
+	 * unique across a project.
+	 * 
+	 * @param aProject
+	 *            A valid, accessible project to contain the component
 	 * @return A handle to an IVirtualComponent that may or may not exist or
 	 *         null if passed project does not contain ModuleCoreNature.
 	 * @deprecated
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ModuleCoreNature.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ModuleCoreNature.java
index 5b8a475..a3704cf 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ModuleCoreNature.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/ModuleCoreNature.java
@@ -13,6 +13,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IProjectNature;
@@ -38,6 +39,7 @@
 import org.eclipse.wst.common.componentcore.internal.impl.ArtifactEditModelFactory;
 import org.eclipse.wst.common.componentcore.internal.impl.ComponentCoreURIConverter;
 import org.eclipse.wst.common.componentcore.internal.impl.ModuleStructuralModelFactory;
+import org.eclipse.wst.common.componentcore.internal.impl.WTPModulesResourceFactory;
 import org.eclipse.wst.common.componentcore.internal.impl.WTPResourceFactoryRegistry;
 import org.eclipse.wst.common.componentcore.internal.util.IModuleConstants;
 import org.eclipse.wst.common.componentcore.internal.util.ModuleCoreMessages;
@@ -165,8 +167,33 @@
 		}
 		return null;
 	}
+	// The existence of this Nature plus the component file on disk makes a flexible project
 	public static boolean isFlexibleProject(IProject project) {
-		return ModuleCoreNature.getModuleCoreNature(project) != null;
+		boolean foundNature = ModuleCoreNature.getModuleCoreNature(project) != null;
+		if (foundNature) {
+			return componentResourceExists(project);
+		}
+		return false;
+	}
+	public static boolean componentResourceExists(IProject project) {
+		
+		IFile compFile = project.getFile(StructureEdit.MODULE_META_FILE_NAME);
+		if (compFile.isAccessible())
+			return true;
+		else { //Need to check for legacy file locations also....
+			compFile = project.getFile(ModuleStructuralModel.R1_MODULE_META_FILE_NAME);
+			if (compFile.isAccessible())
+				return true;
+			else {
+				compFile = project.getFile(ModuleStructuralModel.R0_7_MODULE_META_FILE_NAME);
+				if (compFile.isAccessible())
+					return true;
+				else {
+					compFile = project.getFile(WTPModulesResourceFactory.FIRST_WTP_MODULES_SHORT_NAME);
+					return compFile.isAccessible();
+				}
+			}
+		}
 	}
 
 	/**
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/datamodel/properties/IServerContextRootDataModelProperties.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/datamodel/properties/IServerContextRootDataModelProperties.java
new file mode 100644
index 0000000..c939138
--- /dev/null
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/datamodel/properties/IServerContextRootDataModelProperties.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.common.componentcore.datamodel.properties;
+
+import org.eclipse.wst.common.componentcore.internal.operation.ServerContextRootDataModelProvider;
+
+public interface IServerContextRootDataModelProperties {
+	/**
+	 * This field should not be used.  It is not part of the API and may be modified in the future.
+	 */
+	public static Class _provider_class = ServerContextRootDataModelProvider.class;
+
+	public static final String PROJECT = "IServerContextRootDataModelProperties.PROJECT"; //$NON-NLS-1$	
+	public static final String CONTEXT_ROOT = "IServerContextRootDataModelProperties.CONTEXT_ROOT"; //$NON-NLS-1$
+
+}
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/ModuleStructuralModel.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/ModuleStructuralModel.java
index 9547914..b974268 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/ModuleStructuralModel.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/ModuleStructuralModel.java
@@ -78,8 +78,8 @@
 */ 
 public class ModuleStructuralModel extends EditModel implements IAdaptable {
 	
-	private static final String R0_7_MODULE_META_FILE_NAME = ".component";
-	private static final String R1_MODULE_META_FILE_NAME = ".settings/.component";
+	public static final String R0_7_MODULE_META_FILE_NAME = ".component";
+	public static final String R1_MODULE_META_FILE_NAME = ".settings/.component";
 	public static final String MODULE_CORE_ID = "moduleCoreId"; //$NON-NLS-1$ 
 	private static final String PROJECT_VERSION_1_5 = "1.5.0";
 	private boolean useOldFormat = false;
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/builder/DependencyGraphImpl.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/builder/DependencyGraphImpl.java
index f1842d9..04d8dcd 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/builder/DependencyGraphImpl.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/builder/DependencyGraphImpl.java
@@ -25,7 +25,6 @@
 import org.eclipse.wst.common.componentcore.ComponentCore;
 import org.eclipse.wst.common.componentcore.internal.ModulecorePlugin;
 import org.eclipse.wst.common.componentcore.internal.impl.WTPModulesResourceFactory;
-import org.eclipse.wst.common.componentcore.internal.resources.VirtualComponent;
 import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
 import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
 
@@ -41,12 +40,9 @@
 	 * {A, B} }
 	 */
 	private Map<IProject, Set<IProject>> graph = null;
-	
+
 	private long modStamp = 0;
 
-	private Map<String, Object> referenceOptions = new HashMap<String, Object>();
-	
-	
 	/**
 	 * This is not public; only {@link IDependencyGraph#INSTANCE} should be
 	 * used.
@@ -157,8 +153,6 @@
 	 */
 	private void initGraph() {
 		synchronized (graphLock) {
-			referenceOptions.put("GET_JAVA_REFS", Boolean.FALSE);
-			referenceOptions.put("GET_FUZZY_EAR_REFS", Boolean.FALSE);
 			try {
 				preUpdate();
 				graph = new HashMap<IProject, Set<IProject>>();
@@ -306,7 +300,7 @@
 						for (IProject sourceProject : allProjects) {
 							IVirtualComponent component = ComponentCore.createComponent(sourceProject);
 							if (component != null) {
-								IVirtualReference[] references = component instanceof VirtualComponent ? ((VirtualComponent)component).getReferences(referenceOptions): component.getReferences();
+								IVirtualReference[] references = component.getReferences();
 								for (IVirtualReference ref : references) {
 									IVirtualComponent targetComponent = ref.getReferencedComponent();
 									if (targetComponent != null) {
@@ -326,7 +320,7 @@
 							IVirtualComponent component = ComponentCore.createComponent(sourceProject);
 							if (component != null) {
 								validRefs.clear();
-								IVirtualReference[] references = component instanceof VirtualComponent ? ((VirtualComponent)component).getReferences(referenceOptions): component.getReferences();
+								IVirtualReference[] references = component.getReferences();
 								for (IVirtualReference ref : references) {
 									IVirtualComponent targetComponent = ref.getReferencedComponent();
 									if (targetComponent != null) {
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/IResourceFactoryExtPtConstants.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/IResourceFactoryExtPtConstants.java
index fda1a5c..c6e1e45 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/IResourceFactoryExtPtConstants.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/IResourceFactoryExtPtConstants.java
@@ -26,6 +26,8 @@
 	String ATT_CONTENTTYPEID = "contentTypeId"; //$NON-NLS-1$ 
 	
 	String ATT_ISDEFAULT = "isDefault"; //$NON-NLS-1$ 
+	
+	String ATT_OVERRIDES_FACTORY ="overridesFactoryClass"; //$NON-NLS-1$ 
 		
 
 }
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/WTPResourceFactoryRegistry.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/WTPResourceFactoryRegistry.java
index e0698b2..8c1136d 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/WTPResourceFactoryRegistry.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/impl/WTPResourceFactoryRegistry.java
@@ -11,6 +11,8 @@
 package org.eclipse.wst.common.componentcore.internal.impl;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Set;
 
@@ -26,6 +28,7 @@
 import org.eclipse.core.runtime.SafeRunner;
 import org.eclipse.core.runtime.content.IContentDescription;
 import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.jobs.ILock;
 import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.jem.util.RegistryReader;
@@ -40,6 +43,7 @@
 import org.eclipse.wst.common.internal.emf.resource.ResourceFactoryDescriptor;
 import org.eclipse.wst.common.internal.emf.utilities.DefaultOverridableResourceFactoryRegistry;
 import org.eclipse.wst.common.internal.emfworkbench.WorkbenchResourceHelper;
+import org.eclipse.wst.common.internal.emfworkbench.edit.EMFWorkbenchEditContextFactory;
 
 /**
  * <p>
@@ -63,26 +67,44 @@
 		return WTPResourceFactoryRegistry.INSTANCE.getFactory(uri);	
 	}   
 
-	public synchronized Resource.Factory getFactory(URI uri, IContentDescription description) {
-		Resource.Factory resourceFactory = null;
-		if(uri != null && uri.lastSegment() != null) {
-			ResourceFactoryDescriptor descriptor = null;
-			if(null == description){
-				descriptor = getDescriptor(uri);
-			} else {
-				descriptor = getDescriptor(uri, description);
-			}
-			
-			if(descriptor != null) {
-				resourceFactory = getFactory(descriptor);	
-			}	
+	public Resource.Factory getFactory(URI uri, IContentDescription description) {
+		IProject componentProject = null;
+		try {
+			componentProject = StructureEdit.getContainingProject(uri);
+		} catch (UnresolveableURIException e) {
+			// don't do anything
 		}
-		if(resourceFactory == null)
-			resourceFactory = super.getFactory(uri);
-		return resourceFactory; 
+		ILock lock = EMFWorkbenchEditContextFactory.getProjectLockObject(componentProject);
+		try{
+			if(null != lock){
+				lock.acquire();
+			}
+			synchronized(this){
+				Resource.Factory resourceFactory = null;
+				if(uri != null && uri.lastSegment() != null) {
+					ResourceFactoryDescriptor descriptor = null;
+					if(null == description){
+						descriptor = getDescriptor(uri);
+					} else {
+						descriptor = getDescriptor(uri, description);
+					}
+					
+					if(descriptor != null) {
+						resourceFactory = getFactory(descriptor);	
+					}	
+				}
+				if(resourceFactory == null)
+					resourceFactory = super.getFactory(uri);
+				return resourceFactory;
+			}
+		} finally{
+			if(null != lock){
+				lock.release();
+			}
+		} 
 	}
 	
-	public synchronized Resource.Factory getFactory(URI uri) {
+	public Resource.Factory getFactory(URI uri) {
 		return getFactory(uri, (IContentDescription)null);
 	}	
 
@@ -115,6 +137,11 @@
 		key.shortName = descriptor.getShortSegment();
 		key.type = descriptor.getContentType();
 		key.isDefault = descriptor.isDefault();
+		if(descriptor instanceof ConfigurationResourceFactoryDescriptor){
+			ConfigurationResourceFactoryDescriptor configurationDescriptor = (ConfigurationResourceFactoryDescriptor)descriptor;
+			key.factoryClassName = configurationDescriptor.getFactoryClassName();
+			key.overridesFactoryClassName = configurationDescriptor.getOverridesFactoryClassName();
+		}
 		return key;
 	}
 	
@@ -126,6 +153,8 @@
 		private String shortSegment;
 		private IContentType contentType;
 		private boolean isDefault = true;
+		private String factoryClassName = null;
+		private String overridesFactoryClassName = null;
 		private final IConfigurationElement element; 
 		
 		public ConfigurationResourceFactoryDescriptor(IConfigurationElement ext) throws CoreException {
@@ -134,16 +163,16 @@
 			init();
 		} 
 		
+		public String getOverridesFactoryClassName() {
+			return overridesFactoryClassName;
+		}
+
+		public String getFactoryClassName() {
+			return factoryClassName;
+		}
+
 		private void init() throws CoreException {
 			shortSegment = element.getAttribute(ATT_SHORT_SEGMENT);
-			if(shortSegment == null || shortSegment.trim().length() == 0)
-				throw new CoreException(
-							ModulecorePlugin.createErrorStatus(0, 
-										"The shortSegment attribute of " + TAG_RESOURCE_FACTORY + //$NON-NLS-1$ 
-										" must specify a valid, non-null, non-empty value in " +   //$NON-NLS-1$
-										element.getNamespaceIdentifier(), null));
-			if ("false".equals(element.getAttribute(ATT_ISDEFAULT)))
-					isDefault = false;
 			
 			IConfigurationElement[] bindings = element.getChildren(TAG_CONTENTTYPE);
 			if (bindings.length > 0) {
@@ -151,14 +180,35 @@
 				contentTypeId = bindings[0].getAttribute(ATT_CONTENTTYPEID);			
 				if (contentTypeId != null)
 					contentType = Platform.getContentTypeManager().getContentType(contentTypeId);
-				}
+			}
+			
+			if ((shortSegment == null || shortSegment.trim().length() == 0)
+						&& contentType == null) {
+				throw new CoreException(
+							ModulecorePlugin.createErrorStatus(0, 
+										"Either the shortSegment attribute or the contentType element of " //$NON-NLS-1$
+										+ TAG_RESOURCE_FACTORY 
+										+ " must be specified in " 
+										+ element.getNamespaceIdentifier()
+										+ ".  The shortSegment attribute is specified with a valid, non-null, " //$NON-NLS-1$
+										+ "non-empty value, and the contentType element is specified with a " //$NON-NLS-1$
+										+ "valid, non-null, non-empty contentTypeId." //$NON-NLS-1$
+										, null));
+			}
+			
+			if ("false".equals(element.getAttribute(ATT_ISDEFAULT)))
+				isDefault = false;
+				
+            factoryClassName = element.getAttribute(ATT_CLASS);
+			overridesFactoryClassName = element.getAttribute(ATT_OVERRIDES_FACTORY);				
 		} 
 
 		public boolean isEnabledFor(URI fileURI) {
-			/* shortSegment must be non-null for the descriptor to be created, 
-			 * a validation check in init() verifies this requirement */
-			if(fileURI != null && fileURI.lastSegment() != null)
+			// Not sure where this is actually used, so not sure what the proper 
+			// implementation should be, so simply checking the short segment for now
+			if (fileURI != null && fileURI.lastSegment() != null && shortSegment != null) {
 				return shortSegment.equals(fileURI.lastSegment());
+			}
 			return false;
 		} 
 		
@@ -186,28 +236,37 @@
 		}
 
 		public IContentType getContentType() {
-			
 			return contentType;
 		}
 
 		public boolean isDefault() {
 			return isDefault;
-		}  
+		}
+		
 		public int hashCode() {
-			if (getContentType() != null)
-				return getShortSegment().hashCode() & getContentType().hashCode();
-			else return super.hashCode();
+			int hashCode = 0;
+			if (getContentType() != null) {
+				hashCode |= getContentType().hashCode();
+			}
+			if (getShortSegment() != null) {
+				hashCode |= getShortSegment().hashCode();
+			}
+			return hashCode;
 		}
 		
 		public boolean equals(Object o) {
-			if(o instanceof ResourceFactoryDescriptor && getContentType() != null)
-				return (getShortSegment().equals(((ResourceFactoryDescriptor)o).getShortSegment()) &&
-						getContentType().equals(((ResourceFactoryDescriptor)o).getContentType()));
-			else if (((ResourceFactoryDescriptor)o).getContentType() != null) return false;
-				
-			return super.equals(o);
+			if (! (o instanceof ResourceFactoryDescriptor)) {
+				return false;
+			}
+			ResourceFactoryDescriptor rfdo = (ResourceFactoryDescriptor) o;
+			boolean equals = true;
+			equals &= (getContentType() == null) ? rfdo.getContentType() == null :
+				getContentType().equals(rfdo.getContentType());
+			equals &= (getShortSegment() == null) ? rfdo.getShortSegment() == null :
+				getShortSegment().equals(rfdo.getShortSegment());
+			return equals;
 		}
-	}  
+	}
 	 
 	
 	private class ResourceFactoryRegistryReader extends RegistryReader implements IResourceFactoryExtPtConstants { 
@@ -239,6 +298,8 @@
 	}
 	private class WTPResourceFactoryRegistryKey { 
  		
+		public String overridesFactoryClassName;
+		public String factoryClassName;
 		public String shortName;
 		public IContentType type;
 		public boolean isDefault = true;
@@ -246,44 +307,116 @@
 			super();
 		}
 		
-		
+		/**
+		 * Sort in the following manner:
+		 * First, sort by shortName, if shortName is null, then it comes last
+		 * If shortNames are equal, then sort by isDefault
+		 * If isDefault is also equal, then the one defining a factoryClassName wins
+		 * If both have factoryClassNames, then check to see if one overrides the other via overridesFactoryClassName
+		 * If neither override the other factory class, then sort by factoryClassname
+		 * @param other
+		 * @return
+		 */
+		public int compareTo(WTPResourceFactoryRegistryKey other){
+			if(this == other){
+				return 0;
+			}
+			if(shortName == null && other.shortName == null){
+				return 0;
+			} else if(shortName == null){
+				return 1;
+			} else if(other.shortName == null){
+				return -1;
+			}
+			
+			int shortNameCompare = this.shortName.compareTo(other.shortName);
+			if(shortNameCompare != 0){
+				return shortNameCompare;
+			} else {
+				if(this.isDefault != other.isDefault){
+					if(this.isDefault){
+						return -1;
+					} else {
+						return 1;
+					}
+				} else {
+					if(this.factoryClassName == null && other.factoryClassName == null){
+						return 0;
+					} else if(other.factoryClassName == null){
+						return -1;
+					} else if (this.factoryClassName == null){
+						return 1;
+					} else if(other.factoryClassName.equals(this.overridesFactoryClassName)){
+						return -1;
+					} else if(this.factoryClassName.equals(other.overridesFactoryClassName)){
+						return 1;
+					} else {
+						return this.factoryClassName.compareTo(other.factoryClassName);
+					}	
+				}
+			}
+		}
 	}
 
 	protected void addDescriptor(ResourceFactoryDescriptor descriptor) {
 		getDescriptors().put(getKey(descriptor), descriptor);
 	}
+	
+	private WTPResourceFactoryRegistryKey []  sortedDescriptors = null;
+	
+	private WTPResourceFactoryRegistryKey []  getSortedDescriptorKeys() {
+		if(sortedDescriptors == null || sortedDescriptors.length != getDescriptors().size()){
+			Set keys = getDescriptors().keySet();
+			WTPResourceFactoryRegistryKey [] array = new WTPResourceFactoryRegistryKey [keys.size()];
+			int count = 0;
+			for (Iterator iterator = keys.iterator(); iterator.hasNext();count++) {
+				WTPResourceFactoryRegistryKey key = (WTPResourceFactoryRegistryKey) iterator.next();
+				array[count] = key;
+			}
+			Arrays.sort(array, new Comparator<WTPResourceFactoryRegistryKey>() {
+				public int compare(WTPResourceFactoryRegistryKey key1,
+						WTPResourceFactoryRegistryKey key2) {
+					return key1.compareTo(key2);
+				}
+			});
+			sortedDescriptors = array;
+		}
+		return sortedDescriptors;
+	}
 
 	protected synchronized ResourceFactoryDescriptor getDescriptor(URI uri, IContentDescription description) {
-		Set keys = getDescriptors().keySet();
-		ResourceFactoryDescriptor defaultDesc = null;
-		for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
-			WTPResourceFactoryRegistryKey key = (WTPResourceFactoryRegistryKey) iterator.next();
-			if (key.shortName.equals(uri.lastSegment())) {
-				ResourceFactoryDescriptor desc = (ResourceFactoryDescriptor)getDescriptors().get(key);
-				if (description == null) {
-					if (key.type == null) 
-						return desc;
-					else if (desc.isDefault()) 
-						return desc;
+		WTPResourceFactoryRegistryKey [] keys = getSortedDescriptorKeys();
+		ResourceFactoryDescriptor defaultDescriptor = null;
+		
+		// first check content type
+		if (description != null) {
+			for (WTPResourceFactoryRegistryKey key : keys) {
+				ResourceFactoryDescriptor descriptor = (ResourceFactoryDescriptor) getDescriptors().get(key);
+				
+				if ((key.type != null) && (description.getContentType().equals(key.type))) {
+					if ((defaultDescriptor == null) || (key.isDefault)) {
+						defaultDescriptor = descriptor;
+					}
 				}
-				//Allow the contentType discrimination to take place
-				if ((key.type != null) && 
-						(description != null) && 
-						(description.getContentType().equals(key.type))) {
-					// If the current describer is "default" then specify
-					if(desc.isDefault())
-						return desc;
-					else 	
-						defaultDesc = desc;
-				}
-					
-				if ((description != null) && (desc.isDefault()) && (defaultDesc == null))
-					defaultDesc = desc;
 			}
 		}
-		return defaultDesc;
+		
+		// then check short name, overriding default if necessary
+		for (WTPResourceFactoryRegistryKey key : keys) {
+			ResourceFactoryDescriptor descriptor = (ResourceFactoryDescriptor) getDescriptors().get(key);
+						
+			if ((key.shortName != null) && (uri.lastSegment().equals(key.shortName))) {
+				if ((defaultDescriptor == null) 
+						|| ((description == null) && (key.isDefault))) {
+					defaultDescriptor = descriptor;
+				}
+			}
+		}
+		
+		return defaultDescriptor;
 	}
-private URI newPlatformURI(URI aNewURI, IProject project) {
+	
+	private URI newPlatformURI(URI aNewURI, IProject project) {
 		
 		if (project == null)
 			return ModuleURIUtil.trimToDeployPathSegment(aNewURI);
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/operation/ServerContextRootDataModelProvider.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/operation/ServerContextRootDataModelProvider.java
new file mode 100644
index 0000000..01ded49
--- /dev/null
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/operation/ServerContextRootDataModelProvider.java
@@ -0,0 +1,39 @@
+package org.eclipse.wst.common.componentcore.internal.operation;
+
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+import java.util.Set;
+
+import org.eclipse.wst.common.componentcore.datamodel.properties.IServerContextRootDataModelProperties;
+import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelProvider;
+import org.eclipse.wst.common.frameworks.datamodel.IDataModelOperation;
+
+public class ServerContextRootDataModelProvider 
+ extends AbstractDataModelProvider
+ implements IServerContextRootDataModelProperties{
+
+	public ServerContextRootDataModelProvider(){
+		super();
+	}
+
+	public Set getPropertyNames() {
+		Set names = super.getPropertyNames();
+		names.add(PROJECT);
+		names.add(CONTEXT_ROOT);
+		return names;
+	}
+	
+	public IDataModelOperation getDefaultOperation() {
+		return new ServerContextRootUpdateOperation(model);
+	}
+	
+}
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/operation/ServerContextRootUpdateOperation.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/operation/ServerContextRootUpdateOperation.java
new file mode 100644
index 0000000..962b731
--- /dev/null
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/operation/ServerContextRootUpdateOperation.java
@@ -0,0 +1,45 @@
+package org.eclipse.wst.common.componentcore.internal.operation;
+
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.wst.common.componentcore.ComponentCore;
+import org.eclipse.wst.common.componentcore.datamodel.properties.IServerContextRootDataModelProperties;
+import org.eclipse.wst.common.componentcore.internal.util.IModuleConstants;
+import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
+import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelOperation;
+import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
+
+public class ServerContextRootUpdateOperation 
+ extends  AbstractDataModelOperation 
+ implements IServerContextRootDataModelProperties{
+	
+
+	public ServerContextRootUpdateOperation(IDataModel model) {
+		super(model);
+	}
+
+	public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+		IProject project = (IProject)model.getProperty( IServerContextRootDataModelProperties.PROJECT );
+		String contextRoot = model.getStringProperty( IServerContextRootDataModelProperties.CONTEXT_ROOT );
+		if (contextRoot != null) {
+			IVirtualComponent comp = ComponentCore.createComponent(project);
+			comp.setMetaProperty(IModuleConstants.CONTEXTROOT, contextRoot);	
+		}
+		return OK_STATUS;
+	}
+
+}
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/resources/VirtualResource.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/resources/VirtualResource.java
index 541a609..5f637f9 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/resources/VirtualResource.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/resources/VirtualResource.java
@@ -298,19 +298,22 @@
 		try {
 			moduleCore = StructureEdit.getStructureEditForWrite(getProject());
 			WorkbenchComponent component = moduleCore.getComponent();
-			ResourceTreeRoot root = ResourceTreeRoot.getDeployResourceTreeRoot(component);
-			ComponentResource[] resources = root.findModuleResources(getRuntimePath(), ResourceTreeNode.CREATE_NONE);
-			if (resources.length > 0) {
-				for (int resourceIndx = 0; resourceIndx < resources.length; resourceIndx++) {
-					if (aProjectRelativeLocation.makeAbsolute().equals(resources[resourceIndx].getSourcePath())) {
-						component.getResources().remove(resources[resourceIndx]);
+			if (component != null) {
+				ResourceTreeRoot root = ResourceTreeRoot.getDeployResourceTreeRoot(component);
+				ComponentResource[] resources = root.findModuleResources(getRuntimePath(), ResourceTreeNode.CREATE_NONE);
+				if (resources.length > 0) {
+					for (int resourceIndx = 0; resourceIndx < resources.length; resourceIndx++) {
+						if (aProjectRelativeLocation.makeAbsolute().equals(resources[resourceIndx].getSourcePath())) {
+							component.getResources().remove(resources[resourceIndx]);
+						}
 					}
 				}
 			}
 		}
 		finally {
 			if (moduleCore != null) {
-				moduleCore.saveIfNecessary(monitor);
+				if (component != null)
+					moduleCore.saveIfNecessary(monitor);
 				moduleCore.dispose();
 			}
 		}
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentImplManager.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentImplManager.java
index 2cc2fdc..60a9feb 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentImplManager.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentImplManager.java
@@ -169,6 +169,23 @@
 		return new VirtualComponent(project, new Path("/")); //$NON-NLS-1$
 	}
 
+	public IVirtualComponent createComponent(IProject project, boolean checkSettings) {
+		if  (checkSettings)
+			return createComponent(project);
+		try {
+			IComponentImplFactory factory = findFactoryForProject(project);
+			if(null != factory){
+				return factory.createComponent(project);
+			}
+		} catch (Exception e) {
+			// Just return a default component
+		}
+		if (ModuleCoreNature.getModuleCoreNature(project) == null){
+			return null;
+		}
+		return new VirtualComponent(project, new Path("/")); //$NON-NLS-1$
+	}
+
 	public IVirtualComponent createArchiveComponent(IProject aProject, String aComponentName) {
 		try {
 			IComponentImplFactory factory = findFactoryForProject(aProject);
diff --git a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentUtilities.java b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentUtilities.java
index ba5afa0..0ddeaf9 100644
--- a/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentUtilities.java
+++ b/plugins/org.eclipse.wst.common.modulecore/modulecore-src/org/eclipse/wst/common/componentcore/internal/util/ComponentUtilities.java
@@ -12,8 +12,11 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
@@ -23,6 +26,7 @@
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
@@ -31,6 +35,7 @@
 import org.eclipse.wst.common.componentcore.ComponentCore;
 import org.eclipse.wst.common.componentcore.ModuleCoreNature;
 import org.eclipse.wst.common.componentcore.datamodel.properties.ICreateReferenceComponentsDataModelProperties;
+import org.eclipse.wst.common.componentcore.datamodel.properties.IServerContextRootDataModelProperties;
 import org.eclipse.wst.common.componentcore.internal.Property;
 import org.eclipse.wst.common.componentcore.internal.StructureEdit;
 import org.eclipse.wst.common.componentcore.internal.WorkbenchComponent;
@@ -215,6 +220,18 @@
 		modHandlesList.addAll(targetComponentProjects);
 		model.setProperty(ICreateReferenceComponentsDataModelProperties.TARGET_COMPONENT_LIST, modHandlesList);
 		model.setProperty(ICreateReferenceComponentsDataModelProperties.TARGET_COMPONENTS_DEPLOY_PATH,"/WEB-INF/lib"); //$NON-NLS-1$
+		if(modHandlesList != null){
+			Map map = new HashMap();
+			for(int i=0; i<modHandlesList.size();i++){
+				IVirtualComponent comp = (IVirtualComponent)modHandlesList.get(i);
+				String uri = comp.getName().replace(' ', '_') + ".jar";
+				map.put(comp, uri);
+			}
+			if(map.size() > 0){
+				model.setProperty(ICreateReferenceComponentsDataModelProperties.TARGET_COMPONENTS_TO_URI_MAP, map);
+			}
+		}
+		
 		return new CreateReferenceComponentsOp(model);
 	}
 
@@ -309,9 +326,19 @@
 	 * 
 	 * @param contextRoot string
 	 */
-	public static void setServerContextRoot(IProject project, String contextRoot) {
-		IVirtualComponent comp = ComponentCore.createComponent(project);
-		comp.setMetaProperty(IModuleConstants.CONTEXTROOT, contextRoot);
+	public static void setServerContextRoot(IProject project, String newContextRoot) {
+		
+		IDataModel model = DataModelFactory.createDataModel(IServerContextRootDataModelProperties.class);
+		model.setProperty(IServerContextRootDataModelProperties.PROJECT, project);
+		model.setStringProperty(IServerContextRootDataModelProperties.CONTEXT_ROOT,
+				newContextRoot);
+		
+		try {
+			model.getDefaultOperation().execute(new NullProgressMonitor(), null);
+		}
+		catch (ExecutionException e) {
+			org.eclipse.wst.common.componentcore.internal.ModulecorePlugin.logError(e);
+		}
 	}
 
 	/**
diff --git a/plugins/org.eclipse.wst.common.modulecore/schema/resourceFactories.exsd b/plugins/org.eclipse.wst.common.modulecore/schema/resourceFactories.exsd
index dd43bdb..49f7a80 100644
--- a/plugins/org.eclipse.wst.common.modulecore/schema/resourceFactories.exsd
+++ b/plugins/org.eclipse.wst.common.modulecore/schema/resourceFactories.exsd
@@ -1,16 +1,21 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <!-- Schema file written by PDE -->
-<schema targetNamespace="org.eclipse.wst.common.modulecore">
+<schema targetNamespace="org.eclipse.wst.common.modulecore" xmlns="http://www.w3.org/2001/XMLSchema">
 <annotation>
-      <appInfo>
+      <appinfo>
          <meta.schema plugin="org.eclipse.wst.common.modulecore" id="resourceFactories" name="Resource Factory Association (Internal)"/>
-      </appInfo>
+      </appinfo>
       <documentation>
          An *internal* extension point that declares an association between a short-segment filename and a Resource.Factory.
       </documentation>
    </annotation>
 
    <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
       <complexType>
          <sequence>
             <element ref="resourceFactory"/>
@@ -34,9 +39,9 @@
                <documentation>
                   
                </documentation>
-               <appInfo>
+               <appinfo>
                   <meta.attribute translatable="true"/>
-               </appInfo>
+               </appinfo>
             </annotation>
          </attribute>
       </complexType>
@@ -57,15 +62,15 @@
                <documentation>
                   Declares an implementation of &lt;code&gt;org.eclipse.emf.ecore.resource.Resource.Factory&lt;/code&gt;.
                </documentation>
-               <appInfo>
+               <appinfo>
                   <meta.attribute kind="java" basedOn="org.eclipse.emf.ecore.resource.Resource.Factory"/>
-               </appInfo>
+               </appinfo>
             </annotation>
          </attribute>
-         <attribute name="shortSegment" type="string" use="required">
+         <attribute name="shortSegment" type="string">
             <annotation>
                <documentation>
-                  Declares the short segment of a filename that the resource factory applies to (e.g. &quot;web.xml&quot;).
+                  Optionally declares the short segment of a filename that the resource factory applies to (e.g. &quot;web.xml&quot;).
                </documentation>
             </annotation>
          </attribute>
@@ -76,14 +81,24 @@
                </documentation>
             </annotation>
          </attribute>
+         <attribute name="overridesFactoryClass" type="string">
+            <annotation>
+               <documentation>
+                  This optional attribute is to resolve conflicts between multiple defeault factories registered to the same content type and short segments.  The value should be the fully qualified class name of the factory being overridden.
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn="org.eclipse.emf.ecore.resource.Resource.Factory:"/>
+               </appinfo>
+            </annotation>
+         </attribute>
       </complexType>
    </element>
 
    <element name="contentTypeBinding">
       <annotation>
-         <appInfo>
+         <appinfo>
             <meta.element labelAttribute="contentTypeId"/>
-         </appInfo>
+         </appinfo>
          <documentation>
             Advertises that the containing editor understands the given content type and is suitable for editing files of that type.
          </documentation>
@@ -100,48 +115,40 @@
    </element>
 
    <annotation>
-      <appInfo>
+      <appinfo>
          <meta.section type="since"/>
-      </appInfo>
+      </appinfo>
       <documentation>
          [Enter the first release in which this extension point appears.]
       </documentation>
    </annotation>
 
    <annotation>
-      <appInfo>
+      <appinfo>
          <meta.section type="examples"/>
-      </appInfo>
+      </appinfo>
       <documentation>
          [Enter extension point usage example here.]
       </documentation>
    </annotation>
 
    <annotation>
-      <appInfo>
+      <appinfo>
          <meta.section type="apiInfo"/>
-      </appInfo>
+      </appinfo>
       <documentation>
          [Enter API information here.]
       </documentation>
    </annotation>
 
    <annotation>
-      <appInfo>
+      <appinfo>
          <meta.section type="implementation"/>
-      </appInfo>
+      </appinfo>
       <documentation>
          [Enter information about supplied implementation of this extension point.]
       </documentation>
    </annotation>
 
-   <annotation>
-      <appInfo>
-         <meta.section type="copyright"/>
-      </appInfo>
-      <documentation>
-         
-      </documentation>
-   </annotation>
 
 </schema>
diff --git a/plugins/org.eclipse.wst.validation/.options b/plugins/org.eclipse.wst.validation/.options
index 36a7471..404c71b 100644
--- a/plugins/org.eclipse.wst.validation/.options
+++ b/plugins/org.eclipse.wst.validation/.options
@@ -22,4 +22,16 @@
 # org.eclipse.wst.xml.core.xml 
 org.eclipse.wst.validation/extraValDetail=
 
+# To make debugging easier, you can make it appear is if only one validator has been 
+# registered via the extension points. You do this by setting the following filter
+# to validator id of the one validator that you want registered.
+#
+# As an example, you could use this plug-in id for a v1 validator: org.eclipse.jst.j2ee.ejb.EJBValidator
+# and org.eclipse.wst.html.ui.HTMLValidator for a v2 validator
+org.eclipse.wst.validation/filter/allExcept=
+
+# The tracing level. If not supplied a default of zero is used. The higher the number the
+# more verbose the tracing.
+org.eclipse.wst.validation/trace/level=
+
 
diff --git a/plugins/org.eclipse.wst.validation/META-INF/MANIFEST.MF b/plugins/org.eclipse.wst.validation/META-INF/MANIFEST.MF
index 6053726..ae1a891 100644
--- a/plugins/org.eclipse.wst.validation/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.wst.validation/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name.0
 Bundle-SymbolicName: org.eclipse.wst.validation; singleton:=true
-Bundle-Version: 1.2.2.qualifier
+Bundle-Version: 1.2.6.qualifier
 Bundle-Activator: org.eclipse.wst.validation.internal.plugin.ValidationPlugin
 Bundle-Vendor: %Bundle-Vendor.0
 Bundle-Localization: plugin
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationConstants.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationConstants.java
index 18e6d44..16aef08 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationConstants.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationConstants.java
@@ -35,8 +35,7 @@
 	String ELEMENT_SEPARATOR = ";"; //$NON-NLS-1$ // separates the name of one IValidator from the next in the list of enabled validators for a project or preference
 	String DELEGATES_SEPARATOR = "="; //$NON-NLS-1$ // Separates the delegating validator id from the delegate validator id in the list of delegates
 
-	// The following values must match the attributes in the preference marker as shown in
-	// plugin.xml
+	// The following values must match the attributes in the preference marker as shown in plugin.xml
 	// Even though the plugin.xml values are not used to create new Preference or Project markers,
 	// maintaining one local name ensures that there's no confusion writing the migration code.
 	// These are the QualifiedNames used to persist the user's settings.
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationManager.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationManager.java
index 0c0c0be..47e919c 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationManager.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ConfigurationManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2008 IBM Corporation and others.
+ * Copyright (c) 2001, 2009 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
@@ -15,8 +15,8 @@
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.Preferences;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 
 
@@ -47,10 +47,7 @@
 			if (!marker.getType().equals(VALIDATION_MARKER))return null;
 
 			Object attrib = marker.getAttribute(VALIDATION_MARKER_OWNER);
-			if (attrib == null) {
-				// owner not set
-				return null;
-			}
+			if (attrib == null)return null;
 			return attrib.toString();
 		} catch (CoreException e) {
 			ValidationPlugin.getPlugin().handleException(e);
@@ -93,7 +90,7 @@
 	 * This method returns the global preferences for the workspace.
 	 */
 	public GlobalConfiguration getGlobalConfiguration() throws InvocationTargetException {
-		IWorkspaceRoot root = ValidationConfiguration.getRoot();
+		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
 		GlobalConfiguration gp = null;
 		try {
 			gp = (GlobalConfiguration) root.getSessionProperty(USER_PREFERENCE);
@@ -110,10 +107,8 @@
 			gp = (GlobalConfiguration) root.getSessionProperty(USER_PREFERENCE);
 			if (gp == null) {
 				gp = new GlobalConfiguration(root);
-				Preferences prefs = ValidationPlugin.getPlugin().getPluginPreferences();
-				if( prefs != null ){
-					prefs.addPropertyChangeListener(gp);
-				}
+				PreferencesWrapper prefs = PreferencesWrapper.getPreferences(null, null);
+//				prefs.addPropertyChangeListener(gp);
 				
 				gp.getVersion(); // initialize the configuration's version attribute
 				gp.load(); // initialize this instance from the stored values
@@ -170,8 +165,7 @@
 		try {
 			if (isMigrated(project)) {
 				ProjectConfiguration prjp = ConfigurationManager.getManager().getProjectConfiguration(project);
-				if(!prjp.useGlobalPreference())
-					prjp.store();
+				if(!prjp.useGlobalPreference())prjp.store();
 			}
 		} catch (InvocationTargetException e) {
 			ValidationPlugin.getPlugin().handleException(e);
@@ -180,9 +174,17 @@
 		}
 	}
 
+	/**
+	 * @deprecated this method does not do anything.
+	 * @param project
+	 */
 	public void deleting(IProject project) {
 	}
 
+	/**
+	 * @deprecated this method does not do anything.
+	 * @param project
+	 */
 	public void opening(IProject project) {
 		// Do not load or migrate the project in this method; let the getConfiguration(IProject)
 		// method do that. Do not load the project before it's necessary.
@@ -193,9 +195,7 @@
 	 */
 	public boolean isGlobalMigrated() throws InvocationTargetException {
 		IWorkspaceRoot root = ValidationConfiguration.getRoot();
-		if (root == null) {
-			return false;
-		}
+		if (root == null)return false;
 
 		try {
 			GlobalConfiguration gp = (GlobalConfiguration) root.getSessionProperty(USER_PREFERENCE);
@@ -220,20 +220,17 @@
 	 * Return true if the given project has the current level of metadata, false otherwise.
 	 */
 	public boolean isMigrated(IProject project) throws InvocationTargetException {
-		if (project == null) {
-			return false;
-		}
+		if (project == null)return false;
+		
 		try {
 			if (project.isAccessible()) {
 				ProjectConfiguration prjp = (ProjectConfiguration) project.getSessionProperty(USER_PREFERENCE);
-				if (prjp != null) {
-					return prjp.isVersionCurrent();
-				}
+				if (prjp != null)return prjp.isVersionCurrent();
+				
 				String serializedPrjp = project.getPersistentProperty(USER_PREFERENCE);
 				if (serializedPrjp != null) {
 					prjp = new ProjectConfiguration(project);
-					prjp.getVersion(); // initialize the configuration's
-					// version attribute
+					prjp.getVersion(); 
 					return prjp.isVersionCurrent();
 				}
 			}
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/EventManager.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/EventManager.java
index de77ba9..d603b8d 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/EventManager.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/EventManager.java
@@ -11,8 +11,8 @@
 package org.eclipse.wst.validation.internal;
 
 import java.lang.reflect.InvocationTargetException;
-import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
@@ -39,7 +39,7 @@
 	private IResourceDeltaVisitor _postAutoBuildVisitor;
 	private boolean _isActive; // has the registry been read?
 	
-	private Set<IProjectChangeListener> _listeners = new HashSet<IProjectChangeListener>(4);
+	private Set<IProjectChangeListener> _listeners = new CopyOnWriteArraySet<IProjectChangeListener>();
 
 	private EventManager() {
 	}
@@ -80,7 +80,7 @@
 		signal(project, IProjectChangeListener.ProjectOpened);
 
 		// When the project is opened, check for any orphaned tasks or tasks whose owners need to be updated.
-		ConfigurationManager.getManager().opening(project);
+//		ConfigurationManager.getManager().opening(project);
 	}
 
 	public void closing(IProject project) {
@@ -163,7 +163,7 @@
 					}
 				}
 
-				ConfigurationManager.getManager().deleting(project);
+//				ConfigurationManager.getManager().deleting(project);
 			}
 		} catch (InvocationTargetException e) {
 			ValidationPlugin.getPlugin().handleException(e);
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/FilterUtil.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/FilterUtil.java
index fb2a80d..39a36bc 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/FilterUtil.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/FilterUtil.java
@@ -613,7 +613,7 @@
 
 					IResource resource = subdelta.getResource();
 
-					if (Tracing.isLogging()) {
+					if (Tracing.isLogging(2)) {
 						StringBuffer buffer = new StringBuffer("FilterUtil-01: subdelta of "); //$NON-NLS-1$
 						buffer.append(resource.getName());
 						buffer.append(" has resource delta kind: "); //$NON-NLS-1$
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/GlobalConfiguration.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/GlobalConfiguration.java
index 318de6d..20c044f 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/GlobalConfiguration.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/GlobalConfiguration.java
@@ -47,7 +47,7 @@
 	 * without persisting them (i.e., if the user presses Cancel then nothing needs to be done.)
 	 */
 	public GlobalConfiguration(GlobalConfiguration original) throws InvocationTargetException {
-		super();
+		super(original.getResource());
 		original.copyTo(this);
 	}
 
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ProjectConfiguration.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ProjectConfiguration.java
index b91a777..5f39ecf 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ProjectConfiguration.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ProjectConfiguration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2008 IBM Corporation and others.
+ * Copyright (c) 2001, 2009 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
@@ -11,15 +11,15 @@
 package org.eclipse.wst.validation.internal;
 
 import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
 
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ProjectScope;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.IScopeContext;
 import org.eclipse.wst.validation.internal.delegates.ValidatorDelegateDescriptor;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 import org.osgi.service.prefs.BackingStoreException;
@@ -45,22 +45,21 @@
 		// global list.
 		super(project, extractProjectValidators(convertToArray(ValidationRegistryReader.getReader().getAllValidators()), project));
 
-		// Can't put the call to load() and passivate() in the ValidationConfiguration constructor
-		// due
+		// Can't put the call to load() and passivate() in the ValidationConfiguration constructor due
 		// to the order of initialization.
-		//    1. First the ValidationConfiguration constructor is called, and that loads the stored
-		// values.
+		//    1. First the ValidationConfiguration constructor is called, and that loads the stored values.
 		//    2. Then this class's <init> method is called, and that initializes the "override" field
-		// to the default,
-		//       which may be different than the stored value.
+		//       to the default, which may be different than the stored value.
 	}
 
 	/**
 	 * This constructor is provided only for the Properties page, so that the page can store values
 	 * without persisting them (i.e., if the user presses Cancel then nothing needs to be done.)
+	 * 
+	 * @deprecated
 	 */
 	public ProjectConfiguration(ProjectConfiguration original) throws InvocationTargetException {
-		super();
+		super(original.getResource());
 		original.copyTo(this);
 	}
 
@@ -87,6 +86,10 @@
 			return false;
 		}
 	}
+	
+	public boolean getDoesProjectOverride(){
+		return _doesProjectOverride;
+	}
 
 	public boolean doesProjectOverride() {
 		// If the global preference doesn't allow projects to override, it doesn't matter what the
@@ -478,7 +481,7 @@
 				String disableAllValidation = storedConfiguration.substring(disableAllValidationIndex + ConfigurationConstants.DISABLE_ALL_VALIDATION_SETTING.length(), versionIndex);
 				setDisableAllValidation(Boolean.valueOf(disableAllValidation).booleanValue());
 			} else {
-				setDisableAllValidation(false);;
+				setDisableAllValidation(false);
 			}
 			// project doesn't override the global
 			if (disableAllValidationIndex != -1) {
@@ -582,34 +585,75 @@
   
   public void store() throws InvocationTargetException {
 		IProject project = (IProject) getResource();
-		IScopeContext projectContext = new ProjectScope(project);
-		final IEclipsePreferences pref = projectContext.getNode(ValidationPlugin.PLUGIN_ID);
+		final PreferencesWrapper pref = PreferencesWrapper.getPreferences(project, null);
 		if (pref != null) {
 			try {
-				pref.put(USER_PREFERENCE, serialize());
-				pref.put(USER_MANUAL_PREFERENCE, serializeManualSetting());
-				pref.put(USER_BUILD_PREFERENCE, serializeBuildSetting());
-				pref.put(DELEGATES_PREFERENCE, serializeDelegatesSetting());
+				pref.put(ValidationConfiguration.UserPreference, serialize());
+				pref.put(ValidationConfiguration.UserManualPreference, serializeManualSetting());
+				pref.put(ValidationConfiguration.UserBuildPreference, serializeBuildSetting());
+				pref.put(ValidationConfiguration.DelegatesPreference, serializeDelegatesSetting());
 				pref.flush();
 			} catch (BackingStoreException e) {
-				ValidationPlugin.getPlugin().handleException(e);
+				// A common error is that the project has been closed, in which case there
+				// is nothing that we can do.
+				if (project.isAccessible())ValidationPlugin.getPlugin().handleException(e);
 			}
 		}
 	}
   
   protected void loadPreference() throws InvocationTargetException {
 		IProject project = (IProject) getResource();
-		IScopeContext projectContext = new ProjectScope(project);
-		final IEclipsePreferences prefs = projectContext.getNode(ValidationPlugin.PLUGIN_ID);
-		if (prefs != null) {
-			String storedConfig = prefs.get(USER_PREFERENCE, DefaultValue);
+		final PreferencesWrapper prefs = PreferencesWrapper.getPreferences(project, null);
+		if (prefs.nodeExists()) { 
+			String storedConfig = prefs.get(ValidationConfiguration.UserPreference, DefaultValue);
 			deserialize(storedConfig);
-			String storedManualConfig = prefs.get(USER_MANUAL_PREFERENCE, DefaultValue);
+			String storedManualConfig = prefs.get(ValidationConfiguration.UserManualPreference, DefaultValue);
 			deserializeManual(storedManualConfig);
-			String storedBuildConfig = prefs.get(USER_BUILD_PREFERENCE, DefaultValue);
+			String storedBuildConfig = prefs.get(ValidationConfiguration.UserBuildPreference, DefaultValue);
 			deserializeBuild(storedBuildConfig);
-			String storedDelegatesConfiguration = prefs.get(DELEGATES_PREFERENCE, DefaultValue);
+			String storedDelegatesConfiguration = prefs.get(ValidationConfiguration.DelegatesPreference, DefaultValue);
 			deserializeDelegates(storedDelegatesConfiguration);
 		}
 	}
+  
+  /**
+   * Answer the validator id's that have been enabled for manual validation.
+   * @return null if they are all enabled
+   */
+  Set<String> getEnabledManualValidators(){
+	  return getIds(ValidationConfiguration.UserManualPreference, ConfigurationConstants.ENABLED_MANUAL_VALIDATORS);
+  }
+  
+  /**
+   * Answer the validator id's that have been enabled for build validation.
+   * @return null if they are all enabled
+   */
+  Set<String> getEnabledBuildlValidators(){
+	  return getIds(ValidationConfiguration.UserBuildPreference, ConfigurationConstants.ENABLED_BUILD_VALIDATORS);
+  }
+  
+  /**
+   * A helper method to extract some validator id's from a preference store field.
+   * 
+   * @return null if all the validators are enabled.
+   */
+  private Set<String> getIds(String prefKey, String enabledPhrase){
+	IProject project = (IProject) getResource();
+	final PreferencesWrapper prefs = PreferencesWrapper.getPreferences(project, null);
+	if (prefs == null)return null;
+	
+	String storedConfig = prefs.get(prefKey, DefaultValue);
+	if (storedConfig == null || storedConfig.length() == 0 || storedConfig.equals(DefaultValue))return null;
+	int validationIndex = storedConfig.indexOf(enabledPhrase);
+
+	String ids = storedConfig.substring(validationIndex + enabledPhrase.length(),storedConfig.length());
+
+	StringTokenizer tokenizer = new StringTokenizer(ids, ConfigurationConstants.ELEMENT_SEPARATOR);
+	Set<String> set = new HashSet<String>(20);
+	while (tokenizer.hasMoreTokens())set.add(tokenizer.nextToken());
+	if (set.size() == 0)return null;
+	  
+	return set;
+	  
+  }
 }
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/TaskListUtility.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/TaskListUtility.java
index 7da60d7..1cae3c1 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/TaskListUtility.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/TaskListUtility.java
@@ -225,44 +225,43 @@
 	private static IMarker[] getValidationTasks(IResource resource, int severity, int depth) {
 		IMarker[] tempMarkers = null;
 		int validCount = 0;
+		IMarker[] allMarkers = null;
 		try {
-			IMarker[] allMarkers = null;
-			try {
-				allMarkers = resource.findMarkers(VALIDATION_MARKER, true, depth); // false means
-				// only consider PROBLEM_MARKER, not variants of PROBLEM_MARKER.
-				// Since addTask only adds PROBLEM_MARKER, we don't need
-				// to consider its subtypes.
-			} catch (CoreException e) {
-				if (Tracing.isLogging())ValidationPlugin.getPlugin().handleException(e);
-				return NO_MARKERS;
-			}
+			allMarkers = resource.findMarkers(VALIDATION_MARKER, true, depth);
+		} catch (CoreException e) {
+			if (Tracing.isLogging())ValidationPlugin.getPlugin().handleException(e);
+			return NO_MARKERS;
+		}
 
-			// Now filter in the markers, based on severity type.
-			if (allMarkers.length != 0) {
-				tempMarkers = new IMarker[allMarkers.length];
-				for (int i = 0; i < allMarkers.length; i++) {
-					IMarker marker = allMarkers[i];
-					Integer filterSeverity = (Integer) marker.getAttribute(VALIDATION_MARKER_SEVERITY);
-					if (filterSeverity == null) {
-						// odd...marker wasn't created correctly. How could this happen?
-						// Default to the current severity and add it to the list.
-						try {
-							// 226541 - I was seeing markers with valid severities being reset, so I added this
-							// additional test.
-							if (marker.getAttribute(IMarker.SEVERITY, -1) == -1)
-								marker.setAttribute(IMarker.SEVERITY, getSeverity(severity));
-						} catch (Exception e) {
-							ValidationPlugin.getPlugin().handleException(e);
-							continue;
-						}
-					} else if ((severity & filterSeverity.intValue()) == 0) {
+		// Now filter in the markers, based on severity type.
+		if (allMarkers.length != 0) {
+			tempMarkers = new IMarker[allMarkers.length];
+			for (IMarker marker : allMarkers) {
+				Integer filterSeverity = null;
+				try {
+					filterSeverity = (Integer) marker.getAttribute(VALIDATION_MARKER_SEVERITY);
+				}
+				catch (CoreException e){
+					// Someone may have deleted the marker on us. All we can do is skip it.
+					continue;
+				}
+				if (filterSeverity == null) {
+					// odd...marker wasn't created correctly. How could this happen?
+					// Default to the current severity and add it to the list.
+					try {
+						// 226541 - I was seeing markers with valid severities being reset, so I added this
+						// additional test.
+						if (marker.getAttribute(IMarker.SEVERITY, -1) == -1)
+							marker.setAttribute(IMarker.SEVERITY, getSeverity(severity));
+					} catch (Exception e) {
+						ValidationPlugin.getPlugin().handleException(e);
 						continue;
 					}
-					tempMarkers[validCount++] = marker;
+				} else if ((severity & filterSeverity.intValue()) == 0) {
+					continue;
 				}
+				tempMarkers[validCount++] = marker;
 			}
-		} catch (CoreException e) {
-			ValidationPlugin.getPlugin().handleException(e);
 		}
 
 		if (validCount == 0) {
@@ -284,34 +283,32 @@
 
 	private static IMarker[] getValidationTasks(IResource resource, String[] messageOwners, int depth) {
 		IMarker[] markers = getValidationTasks(resource, IMessage.ALL_MESSAGES, depth);
-		if (markers.length == 0) {
-			return NO_MARKERS;
-		}
+		if (markers.length == 0)return NO_MARKERS;
 
 		IMarker[] temp = new IMarker[markers.length];
 		int validCount = 0;
-		for (int i = 0; i < markers.length; i++) {
-			IMarker marker = markers[i];
-
+		for (IMarker marker : markers) {
+			Object owner = null;
 			try {
-				Object owner = marker.getAttribute(VALIDATION_MARKER_OWNER);
-				if ((owner == null) || !(owner instanceof String)) {
-					// The ValidationMigrator will remove any "unowned" validation markers.
-					continue;
-				}
-
-				for (int j = 0; j < messageOwners.length; j++) {
-					String messageOwner = messageOwners[j];
-					if (((String) owner).equals(messageOwner)) {
-						temp[validCount++] = marker;
-						break;
-					}
-				}
+				owner = marker.getAttribute(VALIDATION_MARKER_OWNER);
 			} catch (CoreException e) {
-				ValidationPlugin.getPlugin().handleException(e);
-				return NO_MARKERS;
+				// eat it -- if it no longer exists there is nothing we can do about it
+			}
+			
+			if ((owner == null) || !(owner instanceof String)) {
+				// The ValidationMigrator will remove any "unowned" validation markers.
+				continue;
+			}
+
+			for (String messageOwner : messageOwners) {
+				if (((String) owner).equals(messageOwner)) {
+					temp[validCount++] = marker;
+					break;
+				}
 			}
 		}
+		
+		if (validCount == 0)return NO_MARKERS;
 
 		IMarker[] result = new IMarker[validCount];
 		System.arraycopy(temp, 0, result, 0, validCount);
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationConfiguration.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationConfiguration.java
index 3c5e616..3ddb087 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationConfiguration.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationConfiguration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2008 IBM Corporation and others.
+ * Copyright (c) 2001, 2009 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,9 +10,6 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 import java.util.HashMap;
@@ -34,6 +31,7 @@
 import org.eclipse.wst.validation.internal.delegates.ValidatorDelegateDescriptor;
 import org.eclipse.wst.validation.internal.delegates.ValidatorDelegatesRegistry;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
+import org.osgi.service.prefs.BackingStoreException;
 
 /**
  * This class represents the user's preference or project settings.
@@ -42,7 +40,7 @@
  * property while the resource is open.
  */
 public abstract class ValidationConfiguration implements IPropertyChangeListener {
-	private IResource 	_resource;
+	private final IResource 	_resource;
 	private boolean 	disableAllValidation = getDisableAllValidation();
 	private String 		_version;
 	
@@ -50,20 +48,26 @@
 	 * Map of all validators configured on the project or installed globally. The value of true
 	 * means that the VMD is enabled, and a value of false means that the VMD is disabled.
 	 */
-	private Map<ValidatorMetaData, Boolean>		_validators;
+	private Map<ValidatorMetaData, Boolean>		_validators = new HashMap<ValidatorMetaData, Boolean>();
 	protected Map<ValidatorMetaData, Boolean> 	manualValidators;
 	protected Map<ValidatorMetaData, Boolean> 	buildValidators;
 	
-	protected String USER_PREFERENCE 		= "USER_PREFERENCE"; //$NON-NLS-1$
-	protected String USER_MANUAL_PREFERENCE = "USER_MANUAL_PREFERENCE"; //$NON-NLS-1$
-	protected String USER_BUILD_PREFERENCE 	= "USER_BUILD_PREFERENCE"; //$NON-NLS-1$
-	protected String DELEGATES_PREFERENCE 	= "DELEGATES_PREFERENCE"; //$NON-NLS-1$
+	protected static final String UserPreference = "USER_PREFERENCE"; //$NON-NLS-1$
+	protected static final String UserBuildPreference = "USER_BUILD_PREFERENCE"; //$NON-NLS-1$
+	protected static final String UserManualPreference = "USER_MANUAL_PREFERENCE"; //$NON-NLS-1$
+	protected static final String DelegatesPreference = "DELEGATES_PREFERENCE"; //$NON-NLS-1$
+	
+	// GRK - I am keeping these "constants" in the off chance that they were used somewhere outside the framework
+	protected String USER_PREFERENCE 		= UserPreference;
+	protected String USER_MANUAL_PREFERENCE = UserManualPreference;
+	protected String USER_BUILD_PREFERENCE 	= UserBuildPreference;
+	protected String DELEGATES_PREFERENCE 	= DelegatesPreference;
 	
 	/**
 	 * The key is the target id, that is the id of the place holder validator. The value is the id 
 	 * of the real validator. 
 	 */
-	private Map<String, String> _delegatesByTarget;
+	private Map<String, String> _delegatesByTarget = new HashMap<String, String>();
 	
 	private static final String DefaultValue = "default_value"; //$NON-NLS-1$
 
@@ -124,29 +128,47 @@
 
 		return result;
 	}
+	
+	/**
+	 * Answer the validators
+	 * @return
+	 */
+	public static Set<String> getValidatorIdsManual(){
+		PreferencesWrapper prefs = PreferencesWrapper.getPreferences(null, null);
+		String config = prefs.get(UserManualPreference, null);
+		return getValidatorIds(config);
+	}
+	
+	public static Set<String> getValidatorIdsBuild(){
+		PreferencesWrapper prefs = PreferencesWrapper.getPreferences(null, null);
+		String config = prefs.get(UserBuildPreference, null);
+		return getValidatorIds(config);
+	}
+	
+	private static Set<String> getValidatorIds(String elements){
+		Set<String> set = new HashSet<String>(50);
+		if (elements != null){
+			StringTokenizer tokenizer = new StringTokenizer(elements, ConfigurationConstants.ELEMENT_SEPARATOR);
+			while (tokenizer.hasMoreTokens())set.add(tokenizer.nextToken());
+		}
+		return set;
+	}
 
 	public static IWorkspaceRoot getRoot() {
 		return ResourcesPlugin.getWorkspace().getRoot();
 	}
-
-	protected ValidationConfiguration() throws InvocationTargetException {
-		_validators = new HashMap<ValidatorMetaData, Boolean>();
-		_delegatesByTarget = new HashMap<String, String>();
+	
+	protected ValidationConfiguration(IResource resource){
+		_resource = resource;
 	}
 
 	protected ValidationConfiguration(IResource resource, ValidatorMetaData[] validators) throws InvocationTargetException {
-		this();
-
 		if (resource == null) {
 			throw new InvocationTargetException(null, ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_EXC_NULLCREATE));
 		}
 
-		setResource(resource);
-		setValidators(validators);
-	}
-
-	private void setResource(IResource resource) {
 		_resource = resource;
+		setValidators(validators);
 	}
 	
 	public boolean isDisableAllValidation() throws InvocationTargetException {
@@ -183,8 +205,9 @@
 		ValidatorMetaData[] result = null;
 		 
 		if( !isDisableAllValidation() ){
-			ValidatorMetaData[] temp = new ValidatorMetaData[numberOfValidators()];
-			for (ValidatorMetaData vmd : getBuildEnabledValidatorsMap().keySet()) {
+			Set<ValidatorMetaData> set = getBuildEnabledValidatorsMap().keySet();
+			ValidatorMetaData[] temp = new ValidatorMetaData[set.size()];
+			for (ValidatorMetaData vmd : set) {
 				Boolean bvalue = getBuildEnabledValidatorsMap().get(vmd);
 				if (bvalue) {
 					// If the validator is enabled
@@ -437,6 +460,7 @@
 
 	/**
 	 * This preference has been migrated; change the version to the current version.
+	 * @deprecated dead code.
 	 */
 	public void markVersionCurrent() {
 		// The version should not be marked current until the migration is complete
@@ -536,27 +560,28 @@
 		System.arraycopy(c, 0, result, 0, length);
 		return result;
 	}
-
+	
 	/**
 	 * Save the values of these fields before the project or workspace is closed.
 	 */
 	public void store() throws InvocationTargetException {
-		Preferences pref = ValidationPlugin.getPlugin().getPluginPreferences();
-		if (pref != null) {
-			try {
-				OutputStream os = new ByteArrayOutputStream();
-				pref.setValue(USER_PREFERENCE, serialize());
-				pref.store(os, USER_PREFERENCE);
-				pref.setValue(USER_MANUAL_PREFERENCE, serializeManualSetting());
-				pref.store(os, USER_MANUAL_PREFERENCE);
-				pref.setValue(USER_BUILD_PREFERENCE, serializeBuildSetting());
-				pref.store(os, USER_BUILD_PREFERENCE);
-				pref.setValue(DELEGATES_PREFERENCE, serializeDelegatesSetting());
-				pref.store(os, DELEGATES_PREFERENCE);
-			} catch (IOException e) {
-				ValidationPlugin.getPlugin().handleException(e);
-			}
+		store(null);
+	}
 
+	/**
+	 * Save the values of these fields before the project or workspace is closed.
+	 */
+	public void store(Boolean persist) throws InvocationTargetException {
+		PreferencesWrapper pref = PreferencesWrapper.getPreferences(null, persist);
+		pref.put(ValidationConfiguration.UserPreference, serialize());
+		pref.put(ValidationConfiguration.UserManualPreference, serializeManualSetting());
+		pref.put(ValidationConfiguration.UserBuildPreference, serializeBuildSetting());
+		pref.put(ValidationConfiguration.DelegatesPreference, serializeDelegatesSetting());
+		try {
+			pref.flush();
+		}
+		catch (BackingStoreException e){
+			throw new InvocationTargetException(e);
 		}
 	}
 
@@ -688,24 +713,22 @@
 		// 1. This is a new workspace and no preferences exist.
 		// 2. This is a migrated workspace and the old preferences have already been created as
 		// persistent properties.
-		Preferences prefs = ValidationPlugin.getPlugin().getPluginPreferences();
-		if (prefs != null) {
-			deserializeAllPrefs(prefs);
-		}
+		PreferencesWrapper prefs = PreferencesWrapper.getPreferences(null, null);
+		deserializeAllPrefs(prefs);
 	}
 
 	/**
 	 * @param prefs
 	 * @throws InvocationTargetException
 	 */
-	private void deserializeAllPrefs(Preferences prefs) throws InvocationTargetException {
-		String storedConfig = prefs.getString(USER_PREFERENCE);
+	private void deserializeAllPrefs(PreferencesWrapper prefs) throws InvocationTargetException {
+		String storedConfig = prefs.get(ValidationConfiguration.UserPreference, null);
 		deserialize(storedConfig);
-		String storedManualConfig = prefs.getString(USER_MANUAL_PREFERENCE);
+		String storedManualConfig = prefs.get(ValidationConfiguration.UserManualPreference, null);
 		deserializeManual(storedManualConfig);
-		String storedBuildConfig = prefs.getString(USER_BUILD_PREFERENCE);
+		String storedBuildConfig = prefs.get(ValidationConfiguration.UserBuildPreference, null);
 		deserializeBuild(storedBuildConfig);
-		String storedDelegatesConfiguration = prefs.getString(DELEGATES_PREFERENCE);
+		String storedDelegatesConfiguration = prefs.get(ValidationConfiguration.DelegatesPreference, null);
 		deserializeDelegates(storedDelegatesConfiguration);
 	}
 	
@@ -723,13 +746,13 @@
 
 	private void deserializeAllPrefs(PropertyChangeEvent event) throws InvocationTargetException {
 		String storedConfig = (String)event.getNewValue();
-		if( event.getProperty().equals(USER_PREFERENCE) ){
+		if( event.getProperty().equals(ValidationConfiguration.UserPreference) ){
 			deserialize(storedConfig);
-		}else if(event.getProperty().equals(USER_MANUAL_PREFERENCE)){
+		}else if(event.getProperty().equals(ValidationConfiguration.UserManualPreference)){
 			deserializeManual(storedConfig);
-		}else if(event.getProperty().equals(USER_BUILD_PREFERENCE)){
+		}else if(event.getProperty().equals(ValidationConfiguration.UserBuildPreference)){
 			deserializeBuild(storedConfig);
-		}else if(event.getProperty().equals(DELEGATES_PREFERENCE)){
+		}else if(event.getProperty().equals(ValidationConfiguration.DelegatesPreference)){
 			deserializeDelegates(storedConfig);
 		}
 	}
@@ -787,7 +810,6 @@
 
 	protected void copyTo(ValidationConfiguration up) throws InvocationTargetException {
 		up.setVersion(getVersion());
-		up.setResource(getResource());
 		up.setValidators(getValidators());
 		up.setDisableAllValidation(isDisableAllValidation());
 		up.setEnabledValidators(getEnabledValidators());
@@ -970,7 +992,7 @@
 				String disableAllValidation = storedConfiguration.substring(disableAllValidationIndex + ConfigurationConstants.DISABLE_ALL_VALIDATION_SETTING.length(),versionIndex);
 				setDisableAllValidation(Boolean.valueOf(disableAllValidation).booleanValue());
 		} else {
-				setDisableAllValidation(false);;
+				setDisableAllValidation(false);
 		}
 		
 	}
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationRegistryReader.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationRegistryReader.java
index 6e3e122..9766048 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationRegistryReader.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidationRegistryReader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2008 IBM Corporation and others.
+ * Copyright (c) 2001, 2009 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
@@ -54,36 +54,40 @@
  * ValidatorManager's loadValidatorMetaData(IProject) method. ValidatorManager delegates the load
  * call to this class, and if this class is null, the singleton is new'ed up, and the registry is
  * read.
- * 
+ * <p>
  * No Validator should need to know about this class. The only class which should call
  * ValidationRegistryReader is ValidatorManager.
- * 
+ * </p>
+ * <p>
  * The Validator itself is initialized in the "initializeValidator" method.
- * 
- * <extension point="org.eclipse.wst.validation.internal.provisional.core.core.validator" id="EJBValidator" name="EJB
- * Validator"> <validator><projectNature id="com.ibm.etools.j2ee.EJBNature" include="false"/>
- * <filter objectClass="org.eclipse.core.resources.IFile" nameFilter = "ejb-jar.xml"/> <filter
- * objectClass="org.eclipse.core.resources.IFile" nameFilter = "*.java"/> <helper
- * class="org.eclipse.wst.validation.internal.provisional.core.core.ejb.workbenchimpl.EJBHelper"/> <run
- * class="org.eclipse.wst.validation.internal.provisional.core.core.ejb.EJBValidator" incremental="false" enabled="false"
- * pass="fast,full" async="false"/> <aggregateValidator class="my.aggregate.ValidatorClass"/>
- * <migrate><validator from="old.class.name" to="new.class.name"/> </migrate> </validator>
- * </extension>
+ * </p>
  */
 public final class ValidationRegistryReader implements RegistryConstants {
-	private static ValidationRegistryReader inst;
+	
+	 /* <extension point="org.eclipse.wst.validation.internal.provisional.core.core.validator" id="EJBValidator" name="EJB
+		 * Validator"> <validator><projectNature id="com.ibm.etools.j2ee.EJBNature" include="false"/>
+		 * <filter objectClass="org.eclipse.core.resources.IFile" nameFilter = "ejb-jar.xml"/> <filter
+		 * objectClass="org.eclipse.core.resources.IFile" nameFilter = "*.java"/> <helper
+		 * class="org.eclipse.wst.validation.internal.provisional.core.core.ejb.workbenchimpl.EJBHelper"/> <run
+		 * class="org.eclipse.wst.validation.internal.provisional.core.core.ejb.EJBValidator" incremental="false" enabled="false"
+		 * pass="fast,full" async="false"/> <aggregateValidator class="my.aggregate.ValidatorClass"/>
+		 * <migrate><validator from="old.class.name" to="new.class.name"/> </migrate> </validator>
+		 * </extension>
+		 */
+	
+	private static ValidationRegistryReader _inst = new ValidationRegistryReader();
 	
 	/** list of all validators registered, with their associated ValidatorMetaData, indexed by project nature id */
-	private Map<String,Set<ValidatorMetaData>> _validators;
+	private final Map<String,Set<ValidatorMetaData>> _validators;
 	
 	// list of all validators, indexed by validator class name,
 	// with the validator's ValidatorMetaData as the value.
 	// Needed by the WorkbenchReporter, because sometimes the
 	// IValidator is not enough to remove all messages from the
 	// task list.
-	private Map<String, ValidatorMetaData> _indexedValidators; 
+	private final Map<String, ValidatorMetaData> _indexedValidators; 
 	
-	private Set<ValidatorMetaData> _defaultEnabledValidators;
+	private final Set<ValidatorMetaData> _defaultEnabledValidators;
 	
 	// Since IProject's contents are all instances of IResource, every type filter for a validator
 	// must be an instance of IResource. This applies to both the rebuildCache pass and to the
@@ -100,12 +104,11 @@
 	 * The registry is read once - when this class is instantiated.
 	 */
 	private ValidationRegistryReader() {
-		super();
 
+		_validators = new HashMap<String,Set<ValidatorMetaData>>();
+		_indexedValidators = new HashMap<String, ValidatorMetaData>();
+		_defaultEnabledValidators = new HashSet<ValidatorMetaData>();
 		try {
-			_validators = new HashMap<String,Set<ValidatorMetaData>>();
-			_indexedValidators = new HashMap<String, ValidatorMetaData>();
-			_defaultEnabledValidators = new HashSet<ValidatorMetaData>();
 
 			// Read the registry and build a map of validators. The key into
 			// the map is the IValidator instance and the value is the ValidatorMetaData
@@ -644,7 +647,7 @@
 		return result;
 	}
 
-	private ValidatorMetaData.MigrationMetaData getMigrationMetaData(IConfigurationElement element, ValidatorMetaData vmd) {
+	private ValidatorMetaData.MigrationMetaData getMigrationMetaData(IConfigurationElement element) {
 		IConfigurationElement[] runChildren = element.getChildren(TAG_MIGRATE);
 		if ((runChildren == null) || (runChildren.length == 0)) {
 			return null;
@@ -659,7 +662,7 @@
 			return null;
 		}
 
-		ValidatorMetaData.MigrationMetaData mmd = vmd.new MigrationMetaData();
+		ValidatorMetaData.MigrationMetaData mmd = new ValidatorMetaData.MigrationMetaData();
 		for (int i = 0; i < migrateChildren.length; i++) {
 			IConfigurationElement migrateChild = migrateChildren[i];
 			String from = migrateChild.getAttribute(ATT_FROM);
@@ -718,12 +721,7 @@
 	 * Returns the singleton ValidationRegistryReader.
 	 */
 	public static ValidationRegistryReader getReader() {
-		if (inst == null) {
-			inst = new ValidationRegistryReader();
-
-			EventManager.getManager().setActive(true);
-		}
-		return inst;
+		return _inst;
 	}
 
 	public static boolean isActivated() {
@@ -739,7 +737,7 @@
 	 */
 	private IExtensionPoint getValidatorExtensionPoint() {
 		IExtensionRegistry registry = Platform.getExtensionRegistry();
-		IExtensionPoint extensionPoint = registry.getExtensionPoint(PLUGIN_ID, VALIDATOR_EXT_PT_ID);
+		IExtensionPoint extensionPoint = registry.getExtensionPoint(ValidationPlugin.PLUGIN_ID, VALIDATOR_EXT_PT_ID);
 		if (extensionPoint == null) {
 			// If this happens it means that someone removed the "validator" extension point
 			// declaration from our plugin.xml file.
@@ -1216,28 +1214,15 @@
 		//
 		// To load a String into the constants space, call intern() on the String.
 		//
-		ValidatorMetaData vmd = new ValidatorMetaData();
-		vmd.addFilters(getFilters(element)); // validator may, or may not, have filters
-		vmd.addProjectNatureFilters(getProjectNatureFilters(element)); // validator may, or may not, specify a project nature
-		vmd.addFacetFilters(getFacetIds(element));//validator may or may not specify the facet
-		vmd.setEnablementElement(getEnablementElement(element));
-		vmd.addAggregatedValidatorNames(getAggregateValidatorsNames(element)); // if a validator
-		// aggregated another validator, it should identify
-		// the sub-validator(s)' class name
-		vmd.setValidatorDisplayName(validatorName.intern()); // validator must have a display name.
-		vmd.setValidatorUniqueName(validatorImplName.intern());
-		vmd.setPluginId(pluginId);
-		vmd.setIncremental(getIncremental(element));
-		vmd.setFullBuild(getFullBuild(element));
-		vmd.setAsync(getAsync(element));
-		vmd.setRuleGroup(getRuleGroup(element));
-		vmd.setEnabledByDefault(getEnabledByDefault(element));
-		vmd.setMigrationMetaData(getMigrationMetaData(element, vmd));
-		vmd.setHelperClass(element, helperImplName);
-		vmd.setValidatorClass(runChildren[0]); // associate the above attributes with the validator
-		vmd.addDependentValidator(getDependentValidatorValue(element));
-		vmd.setContentTypeIds(getContentTypeBindings(element));
-		initializeValidatorCustomMarkers(element, pluginId, vmd);
+		
+		boolean async = getAsync(element);
+		String[] markerIds = initializeValidatorCustomMarkers(element, pluginId);
+		ValidatorMetaData vmd = new ValidatorMetaData(async, getAggregateValidatorsNames(element), getEnabledByDefault(element),
+				getIncremental(element), getFullBuild(element), element, helperImplName, getMigrationMetaData(element),
+				pluginId, getRuleGroup(element), runChildren[0], validatorName.intern(), validatorImplName.intern(),
+				getContentTypeBindings(element), getDependentValidatorValue(element), getEnablementElement(element),
+				getFacetIds(element), getFilters(element), getProjectNatureFilters(element), markerIds);
+		
 		
 		if (Tracing.isTraceV1()) {
 			Tracing.log("ValidationRegistryReader-10: validator loaded: " + validatorImplName); //$NON-NLS-1$
@@ -1251,10 +1236,11 @@
 	 * @param pluginId
 	 * @param vmd
 	 */
-	private void initializeValidatorCustomMarkers(IConfigurationElement element, String pluginId, ValidatorMetaData vmd) {
+	private String[] initializeValidatorCustomMarkers(IConfigurationElement element, String pluginId) {
+		String[] qualifiedMarkerIds = null;
 		String[] customMarkerIds = getMarkerIdsValue(element);
 		if (customMarkerIds != null && customMarkerIds.length > 0) {
-			String[] qualifiedMarkerIds = new String[customMarkerIds.length];
+			qualifiedMarkerIds = new String[customMarkerIds.length];
 			for (int i = 0; i < customMarkerIds.length; i++) {
 				String markerid = customMarkerIds[i];
 				if (markerid.lastIndexOf(".") != -1) { //$NON-NLS-1$
@@ -1267,8 +1253,8 @@
 				} else
 					qualifiedMarkerIds[i] = pluginId + "." + customMarkerIds[i]; //$NON-NLS-1$
 			}
-			vmd.setMarkerIds(qualifiedMarkerIds);
 		}
+		return qualifiedMarkerIds;
 	}
 
 	private Expression getEnablementElement(IConfigurationElement element) {
@@ -1319,12 +1305,14 @@
 				// The PropertyPage, and other status messages, need to have a displayable name for
 				// the validator.
 				String pluginId = extension.getContributor().getName();
-				ValidatorMetaData vmd = initializeValidator(element, label, pluginId);
-
-				if (vmd != null) {
-					// Add this validator to the list of validators; if vmd is null, the validator
-					// couldn't be created.
-					add(vmd);
+				if (Tracing.isEnabled(extension.getUniqueIdentifier())){
+					ValidatorMetaData vmd = initializeValidator(element, label, pluginId);
+	
+					if (vmd != null) {
+						// Add this validator to the list of validators; if vmd is null, the validator
+						// couldn't be created.
+						add(vmd);
+					}
 				}
 			}
 		}
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidatorMetaData.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidatorMetaData.java
index ceb7425..0d0b518 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidatorMetaData.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/ValidatorMetaData.java
@@ -18,6 +18,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.core.expressions.Expression;
 import org.eclipse.core.resources.IContainer;
@@ -43,68 +44,70 @@
  * ValidatorMetaData; it is for use by the base framework only.
  */
 public class ValidatorMetaData {
-	private ValidatorFilter[] 		_filters;
-	private ValidatorNameFilter[] 	_projectNatureFilters;
-	private String[] 				_facetFilters;
-	private IValidator 				_validator;
-	private IWorkbenchContext 		_helper;
-	private String 					_validatorDisplayName;
-	private String 			_validatorUniqueName;
-	private String[] 		_aggregatedValidators;
-    private String[] 		_contentTypeIds = null;
-	private String[] 		_validatorNames;
-	private String 			_pluginId;
-	private boolean 		_supportsIncremental = RegistryConstants.ATT_INCREMENTAL_DEFAULT;
-	private boolean 		_supportsFullBuild = RegistryConstants.ATT_FULLBUILD_DEFAULT;
-	private boolean 		_isEnabledByDefault = RegistryConstants.ATT_ENABLED_DEFAULT;
-	private MigrationMetaData _migrationMetaData;
-	private int 			_ruleGroup = RegistryConstants.ATT_RULE_GROUP_DEFAULT;
-	private boolean 		_async = RegistryConstants.ATT_ASYNC_DEFAULT;
-	private boolean 		_dependentValidator = RegistryConstants.DEP_VAL_VALUE_DEFAULT;
-	private String[] 		_markerIds;
-	private String 			_helperClassName;
-	private IConfigurationElement _helperClassElement;
-	private IConfigurationElement _validatorClassElement;
-	private boolean 		_cannotLoad;
-	private boolean 		_manualValidation = true;
-	private boolean 		_buildValidation = true;
-	private Map<IValidatorJob, IWorkbenchContext> _helpers = 
-		Collections.synchronizedMap( new HashMap<IValidatorJob, IWorkbenchContext>() );
-	private Expression 		_enablementExpression;
-
-	ValidatorMetaData() {
-	}
-
+	private final ValidatorFilter[] _filters;
+	private final ValidatorNameFilter[] 	_projectNatureFilters;
+	private final String[]			_facetFilters;
+	private final AtomicReference<IValidator>	_validator = new AtomicReference<IValidator>();
+	private final AtomicReference<IWorkbenchContext> 		_helper = new AtomicReference<IWorkbenchContext>();
+	private final String 			_validatorDisplayName;
+	private final String 			_validatorUniqueName;
+	
 	/**
-	 * Add to the list of class names of every validator which this validator aggregates. For
+	 * The list of class names of every validator which this validator aggregates. For
 	 * example, if the EJB Validator instantiated another validator, and started its validate
 	 * method, then that instantiated class' name should be in this list.
 	 */
-	void addAggregatedValidatorNames(String[] val) {
-		_aggregatedValidators = val;
-	}
+	private final String[] 	_aggregatedValidators;
+    private final String[] 	_contentTypeIds;
+	private final String[] 	_validatorNames;
+	private final String 	_pluginId;
+	private final boolean	_supportsIncremental;
+	private final boolean 	_supportsFullBuild;
+	private final boolean 	_isEnabledByDefault;
+	private final MigrationMetaData _migrationMetaData;
+	private final int 		_ruleGroup;
+	private final boolean 	_async;
+	private final boolean 	_dependentValidator;
+	private final String[]	_markerIds;
+	private final String 	_helperClassName;
+	private final IConfigurationElement _helperClassElement;
+	private final IConfigurationElement _validatorClassElement;
+	private volatile boolean 	_cannotLoad;
+	private volatile boolean 	_manualValidation = true;
+	private volatile boolean	_buildValidation = true;
+	private final Map<IValidatorJob, IWorkbenchContext> _helpers = 
+		Collections.synchronizedMap( new HashMap<IValidatorJob, IWorkbenchContext>() );
+	private final Expression 		_enablementExpression;
 
-	/**
-	 * Add the name/type filter pair(s).
-	 */
-	void addFilters(ValidatorFilter[] filters) {
+	ValidatorMetaData(boolean async, String[] aggregatedValidators, boolean isEnabledByDefault, boolean supportsIncremental,
+			boolean supportsFullBuild, IConfigurationElement helperClassElement, String helperClassName, 
+			MigrationMetaData migrationMetaData, String pluginId, int ruleGroup, IConfigurationElement validatorClassElement,
+			String validatorDisplayName, String validatorUniqueName, String[] contentTypeIds, boolean dependentValidator,
+			Expression enablementExpression, String[] facetFilters, ValidatorFilter[] filters,
+			ValidatorNameFilter[] projectNatureFilters, String[] markerIds) {
+		_async = async;
+		_aggregatedValidators = aggregatedValidators;
+		_isEnabledByDefault = isEnabledByDefault;
+		_supportsIncremental = supportsIncremental;
+		_supportsFullBuild = supportsFullBuild;
+		_helperClassElement = helperClassElement;
+		_helperClassName = helperClassName;
+		_migrationMetaData = migrationMetaData;
+		_pluginId = pluginId;
+		_ruleGroup = ruleGroup;
+		_validatorClassElement = validatorClassElement;
+		_validatorDisplayName = validatorDisplayName;
+		_validatorUniqueName = validatorUniqueName;
+		_contentTypeIds = contentTypeIds;
+		_dependentValidator = dependentValidator;
+		_enablementExpression = enablementExpression;
+		_facetFilters = facetFilters;
 		_filters = filters;
+		_projectNatureFilters = projectNatureFilters;
+		_markerIds = markerIds;
+		_validatorNames = buildValidatorNames();
 	}
-
-	/**
-	 * Add the project nature filter(s).
-	 */
-	void addProjectNatureFilters(ValidatorNameFilter[] filters) {
-		_projectNatureFilters = filters;
-	}
-	
-	/**
-	 * Add the facet  filter(s).
-	 */
-	protected void addFacetFilters(String[] filters) {
-		_facetFilters = filters;
-	}
-	
+		
 	protected String[] getFacetFilters() {
 		return _facetFilters;
 	}
@@ -126,16 +129,18 @@
 	 * Return the list of class names of the primary validator and its aggregates.
 	 */
 	public String[] getValidatorNames() {
-		if (_validatorNames == null) {
-			int aLength = (_aggregatedValidators == null) ? 0 : _aggregatedValidators.length;
-			_validatorNames = new String[aLength + 1]; // add 1 for the primary validator name
-			_validatorNames[0] = getValidatorUniqueName();
-			if (_aggregatedValidators != null) {
-				System.arraycopy(_aggregatedValidators, 0, _validatorNames, 1, aLength);
-			}
-		}
 		return _validatorNames;
 	}
+	
+	private String[] buildValidatorNames() {
+		int aLength = (_aggregatedValidators == null) ? 0 : _aggregatedValidators.length;
+		String [] validatorNames = new String[aLength + 1]; // add 1 for the primary validator name
+		validatorNames[0] = getValidatorUniqueName();
+		if (_aggregatedValidators != null) {
+			System.arraycopy(_aggregatedValidators, 0, validatorNames, 1, aLength);
+		}
+		return validatorNames;
+	}
 
 	/**
 	 * Return the list of class names of every validator which this validator aggregates. For
@@ -191,30 +196,21 @@
 	//TODO just want to remember to figure out the many-temporary-objects problem if this method
 	// continues to new an IValidationContext every time - Ruth
 	public IWorkbenchContext getHelper(IProject project) throws InstantiationException {
-		if (_helper == null) {
-			_helper = ValidationRegistryReader.createHelper(_helperClassElement, _helperClassName);
-			if (_helper == null) {
-				_helper = new WorkbenchContext();
-				//setCannotLoad();
-				//throw new InstantiationException(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_EXC_DISABLEH, new String[]{_helperClassName, getValidatorUniqueName()}));
-			}
-			// Won't be using the element & name again, so clear them.
-			//_helperClassElement = null;
-			//_helperClassName = null;
+		IWorkbenchContext helper = _helper.get();
+		if (helper != null)return helper;
+		
+		helper = ValidationRegistryReader.createHelper(_helperClassElement, _helperClassName);
+		if (helper == null)helper = new WorkbenchContext();
+		
+		if ((helper.getProject() == null) || !(helper.getProject().equals(project))) {
+			helper.setProject(project);
 		}
-		if ((_helper.getProject() == null) || !(_helper.getProject().equals(project))) {
-			// Initialize helper with the new project
-			_helper.setProject(project);
-		}
-		return _helper;
+		if (_helper.compareAndSet(null, helper))return helper;
+		return _helper.get();
 	}
 
 	/**
 	 * cannotLoad is false if both the IValidator and IWorkbenchContext instance can be instantiated.
-	 * This method should be called only by the validation framework, and only if an
-	 * InstantiationException was thrown.
-	 * 
-	 * @param can
 	 */
 	private void setCannotLoad() {
 		_cannotLoad = true;
@@ -251,23 +247,19 @@
 	 * This method returns the validator if it can be loaded; if the validator cannot be loaded,
 	 * e.g., if its plugin is disabled for some reason, then this method throws an
 	 * InstantiationException. Before the CoreException is thrown, this validator is disabled.
-	 * 
-	 * @return IValidator
-	 * @throws InstantiationException
 	 */
 	public IValidator getValidator() throws InstantiationException {
-		if (_validator == null) {
-			_validator = ValidationRegistryReader.createValidator(_validatorClassElement, getValidatorUniqueName());
+		IValidator val = _validator.get();
+		if (val != null)return val;
+		
+		val = ValidationRegistryReader.createValidator(_validatorClassElement, getValidatorUniqueName());
 
-			// Since the element won't be used any more, clear it.
-			//_validatorClassElement = null;
-
-			if (_validator == null) {
-				setCannotLoad();
-				throw new InstantiationException(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_EXC_DISABLEV, new String[]{getValidatorUniqueName()}));
-			}
+		if (val == null) {
+			setCannotLoad();
+			throw new InstantiationException(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_EXC_DISABLEV, new String[]{getValidatorUniqueName()}));
 		}
-		return _validator;
+		if (_validator.compareAndSet(null, val))return val;
+		return _validator.get();
 	}
 
 	public String getValidatorDisplayName() {
@@ -297,8 +289,9 @@
 	 */
 	public boolean isApplicableTo(IResource resource, int resourceDelta) {
 		// If no filters are specified, then every type of resource should be validated/trigger a
-		// rebuild of the model cache
-		if (_filters == null)return true;
+		// rebuild of the model cache.
+		// Also make sure no content type id is specified (BUG 193816)
+		if (_filters == null  && getContentTypeIds() == null)return true;
 
 		return isApplicableTo(resource, resourceDelta, _filters);
 	}
@@ -308,15 +301,14 @@
 	 */
 	boolean isApplicableTo(IResource resource, int resourceDelta, ValidatorFilter[] filters) {
 		// Are any of the filters satisfied? (i.e., OR them, not AND them.)
-		if (checkIfValidSourceFile(resource)) {
-			for (int i = 0; i < filters.length; i++) {
-				ValidatorFilter filter = filters[i];
+		// make sure filters is not null (BUG 193816)
+		if (filters != null && checkIfValidSourceFile(resource)) {
+			for (ValidatorFilter filter : filters) {
 				if (filter.isApplicableType(resource)
 						&& filter.isApplicableName(resource)
 						&& filter.isApplicableAction(resourceDelta)) {
 					return true;
 				}
-
 			}
 		}
 		if (getContentTypeIds() != null) {
@@ -327,10 +319,8 @@
 			} catch (CoreException e) {
 				//Resource exceptions
 			}
-			if (description == null)
-				return false;
-			if (isApplicableContentType(description))
-				return true;
+			if (description == null)return false;
+			if (isApplicableContentType(description))return true;
 		}
 		return false;
 	}
@@ -415,57 +405,11 @@
 		return _async;
 	}
 
-	void setHelperClass(IConfigurationElement element, String helperClassName) {
-		_helperClassElement = element;
-		_helperClassName = helperClassName;
-	}
-
-	void setEnabledByDefault(boolean enabledByDefault) {
-		_isEnabledByDefault = enabledByDefault;
-	}
-
-	void setIncremental(boolean isIncremental) {
-		_supportsIncremental = isIncremental;
-	}
-
-	void setFullBuild(boolean fullBuild) {
-		_supportsFullBuild = fullBuild;
-	}
-
-	void setAsync(boolean isAsync) {
-		_async = isAsync;
-	}
-
-	void setMigrationMetaData(MigrationMetaData mmd) {
-		_migrationMetaData = mmd;
-	}
-
-	void setRuleGroup(int ruleGroup) {
-		_ruleGroup = ruleGroup;
-	}
-
-	void setValidatorClass(IConfigurationElement element) {
-		_validatorClassElement = element;
-		// validator class name == validatorUniqueName
-	}
-
-	void setValidatorDisplayName(String validatorName) {
-		_validatorDisplayName = validatorName;
-	}
-
-	void setValidatorUniqueName(String validatorUniqueName) {
-		_validatorUniqueName = validatorUniqueName;
-	}
-
-	void setPluginId(String validatorPluginId) {
-		_pluginId = validatorPluginId;
-	}
-
 	public String toString() {
 		return getValidatorUniqueName();
 	}
 
-	public class MigrationMetaData {
+	public final static class MigrationMetaData {
 		private Set<String[]> _ids;
 
 		public MigrationMetaData() {
@@ -485,10 +429,6 @@
 		}
 	}
 
-	public void addDependentValidator(boolean b) {
-		_dependentValidator = b;
-	}
-
 	public boolean isDependentValidator() {
 		return _dependentValidator;
 	}
@@ -500,20 +440,12 @@
 		return _markerIds;
 	}
 
-	/**
-	 * @param markerId
-	 *            The markerId to set.
-	 */
-	public void setMarkerIds(String[] markerId) {
-		this._markerIds = markerId;
-	}
-
 	public boolean isBuildValidation() {
 		return _buildValidation;
 	}
 
 	public void setBuildValidation(boolean buildValidation) {
-		this._buildValidation = buildValidation;
+		_buildValidation = buildValidation;
 	}
 
 	public boolean isManualValidation() {
@@ -521,7 +453,7 @@
 	}
 
 	public void setManualValidation(boolean manualValidation) {
-		this._manualValidation = manualValidation;
+		_manualValidation = manualValidation;
 	}
   
 	/**
@@ -589,18 +521,10 @@
 		return _enablementExpression;
 	}
 
-   public void setEnablementElement(Expression enablementElement) {
-	 _enablementExpression = enablementElement;
-	}
-
 public String[] getContentTypeIds() {
 	return _contentTypeIds;
 }
 
-public void setContentTypeIds(String[] contentTypeIds) {
-	this._contentTypeIds = contentTypeIds;
-}
-
  
 private boolean isApplicableContentType(IContentDescription desc){
 	
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/delegates/ValidatorDelegatesRegistryReader.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/delegates/ValidatorDelegatesRegistryReader.java
index 264e26e..368f267 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/delegates/ValidatorDelegatesRegistryReader.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/delegates/ValidatorDelegatesRegistryReader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * Copyright (c) 2006, 2008 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,12 +12,15 @@
 package org.eclipse.wst.validation.internal.delegates;
 
 import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IContributor;
 import org.eclipse.core.runtime.IExtensionPoint;
 import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 
 /**
- * This class reads the plugin extension registry and registers each delegating
+ * This class reads the plug-in extension registry and registers each delegating
  * validator descriptor with the delegates registry.
  * 
  * @see ValidatorDelegatesRegistry
@@ -103,12 +106,19 @@
 
     if (point != null)
     {
-      IConfigurationElement[] elements = point.getConfigurationElements();
-
-      for (int index = 0; index < elements.length; index++)
-      {
-        readElement(elements[index]);
-      }
-    }
+			IConfigurationElement[] elements = point.getConfigurationElements();
+			for (IConfigurationElement configurationElement : elements) {
+				try {
+					readElement(configurationElement);
+				}
+				catch (Exception e) {
+					// we don't want all the validators to be rendered helpless by some 
+					// rogue contribution, so, we catch any exception that occurs during 
+					// initialization, log it, and continue on.
+					IContributor contributor = configurationElement.getContributor();
+					ValidationPlugin.getPlugin().logMessage(IStatus.ERROR, "Rogue validator delegate from " + contributor);
+				}
+			}
+		}
   }
 }
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ManualValidatorsOperation.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ManualValidatorsOperation.java
index 4f22ced..03a0bf2 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ManualValidatorsOperation.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ManualValidatorsOperation.java
@@ -20,11 +20,13 @@
  * ValidationOperation, because some initialization of the validator, and handling of error
  * conditions, is done in the operation. The initialization is separated because some of the
  * information needed to initialize the validator (i.e., the project) isn't known until runtime.
- * 
+ * <p>
  * Instances of this operation run every enabled validator (both full and incremental) on the
  * project.
- * 
+ * </p>
+ * <p>
  * This operation is not intended to be subclassed outside of the validation framework.
+ * </p>
  */
 public class ManualValidatorsOperation extends ValidatorSubsetOperation {
 
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationBuilder.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationBuilder.java
index 51da556..5bb1c28 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationBuilder.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2008 IBM Corporation and others.
+ * Copyright (c) 2001, 2009 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
@@ -12,6 +12,7 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -22,15 +23,16 @@
 import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.wst.validation.ValidationFramework;
 import org.eclipse.wst.validation.internal.ConfigurationManager;
 import org.eclipse.wst.validation.internal.InternalValidatorManager;
 import org.eclipse.wst.validation.internal.ProjectConfiguration;
 import org.eclipse.wst.validation.internal.ResourceConstants;
 import org.eclipse.wst.validation.internal.ResourceHandler;
+import org.eclipse.wst.validation.internal.Tracing;
 import org.eclipse.wst.validation.internal.ValBuilderJob;
 import org.eclipse.wst.validation.internal.ValManager;
-import org.eclipse.wst.validation.internal.ValOperationManager;
 import org.eclipse.wst.validation.internal.ValidatorMetaData;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 
@@ -49,13 +51,22 @@
  * </p>
  */
 public class ValidationBuilder extends IncrementalProjectBuilder {
+	/*
+	 * GRK - This class serves as a main entry point into the framework. There is one instance of this class for every
+	 * project that has a validation builder configured for it. Typically if you had ten projects in your workspace you would have
+	 * ten of these objects. They are created early in the life cycle of the workbench, and then are reused. 
+	 * 
+	 * My observation was that they are run serially by the same thread.
+	 */
 	public static final int NO_DELTA_CHANGE = -1;
 	protected List<IProject> referencedProjects;
 	protected IWorkbenchContext workbenchContext = null;
 	
-	/** All the jobs that the validation framework spawns will belong to this family. */
+	/** 
+	 * All the jobs that the validation framework spawns will belong to this family. 
+	 */
 	public static final Object FAMILY_VALIDATION_JOB = new Object();
-
+	
 	public ValidationBuilder() {
 	}
 
@@ -100,8 +111,10 @@
 	}
 
 	protected void clean(IProgressMonitor monitor) throws CoreException {
-		newClean(monitor);
 		IProject currentProject = getProject();
+		Tracing.log("ValidationBuilder-02 clean ", currentProject); //$NON-NLS-1$
+
+		newClean(monitor);
 		if (currentProject == null || !currentProject.isAccessible())return;
 		try {
 			ProjectConfiguration prjp = ConfigurationManager.getManager().getProjectConfiguration(currentProject);
@@ -125,9 +138,15 @@
 		return referencedProjects.toArray(refProjArray);
 	}
 	
+	@SuppressWarnings("unchecked")
 	public IProject[] build(int kind, Map parameters, IProgressMonitor monitor) {
 		IResourceDelta delta = null;
 		IProject project = getProject();
+		Tracing.log("ValidationBuilder-01 build ", kind, project);  //$NON-NLS-1$
+		if (Tracing.isLogging(1)){
+			Tracing.logResourceDeltas(getDelta(project), 50);
+		}
+		
 		// GRK I wonder why this builder needs to know about all the other referenced projects?
 		// won't they have builders of their own.
 		IProject[] referenced = getAllReferencedProjects(project, null);
@@ -159,11 +178,14 @@
 				return referenced;
 			}
 			if (doFullBuild) {
+				cleanupReferencedProjectsMarkers(prjp, referenced);
 				performFullBuild(monitor, prjp);
 			} else {
 				if (delta.getAffectedChildren().length == 0) {
-					if (isReferencedProjectInDelta(referenced))
+					if (isReferencedProjectInDelta(referenced)){
+						cleanupReferencedProjectsMarkers(prjp, referenced);
 						performFullBuildForReferencedProjectChanged(monitor, prjp);
+					}
 					return referenced;
 				}
 				EnabledIncrementalValidatorsOperation operation = new EnabledIncrementalValidatorsOperation(project, delta, true);
@@ -181,6 +203,39 @@
 			referencedProjects = null;
 		}
 	}
+	
+	private void cleanupReferencedProjectsMarkers(final ProjectConfiguration prjp, IProject[] referenced){
+		//When a project references one or more project, performing a clean build on referenced
+		//causes delta to be invoked on referencee, aka, parent. This causes following code to
+		//be invoked.
+		//The following code is trying to fix a case where Ejb project references a utility project,
+		//and the clean build on utility project causes the code to come here, the ejb validator runs
+		//on the ejb  project due to performFullBuildForReferencedProjectChanged() below, but it also
+		//causes marker to be generated for the util project, but the markers for util project are not
+		//cleaned up.   
+		
+		if( referenced == null || referenced.length == 0 )return;
+		
+		try{
+			ValidatorMetaData[] enabledValidators = prjp.getEnabledFullBuildValidators(true, false);
+ 
+			Set<ValidatorMetaData>  set = new HashSet<ValidatorMetaData>();
+			set.addAll( Arrays.asList( enabledValidators ) );
+			for (IProject p : referenced) {
+				if (!p.isAccessible())continue;
+				ProjectConfiguration refProjectCfg = ConfigurationManager.getManager().getProjectConfiguration(p);
+		
+				ValidatorMetaData[] refEnabledValidators = refProjectCfg.getEnabledFullBuildValidators(true, false);
+				
+				//remove from the set the validators which are also in child
+				for(ValidatorMetaData vmd : refEnabledValidators)set.remove(vmd);
+				
+				for(ValidatorMetaData vmd : set)WorkbenchReporter.removeAllMessages(p, vmd.getValidator());		
+			}	
+		}catch (Exception exc) {
+			ValidationPlugin.getPlugin().logMessage(IStatus.ERROR, exc.toString());
+	}
+}
 
 	private boolean isReferencedProjectInDelta(IProject[] referenced) {
 		IProject p = null;
@@ -204,7 +259,7 @@
 	private void performFullBuild(IProgressMonitor monitor, ProjectConfiguration prjp, boolean onlyDependentValidators) throws InvocationTargetException {
 		ValidatorMetaData[] enabledValidators = prjp.getEnabledFullBuildValidators(true, onlyDependentValidators);
 		if ((enabledValidators != null) && (enabledValidators.length > 0)) {
-			Set enabledValidatorsSet = InternalValidatorManager.wrapInSet(enabledValidators);
+			Set<ValidatorMetaData> enabledValidatorsSet = InternalValidatorManager.wrapInSet(enabledValidators);
 			EnabledValidatorsOperation op = new EnabledValidatorsOperation(getProject(), enabledValidatorsSet, true);
 			op.run(monitor);
 		}
@@ -233,7 +288,7 @@
 				break;
 		}
 		
-		ValBuilderJob.validateProject(project, delta, kind, ValOperationManager.getDefault().getOperation());		
+		ValBuilderJob.validateProject(project, delta, kind);		
 	}
 	
 	
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationOperation.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationOperation.java
index d56d6cb..045be17 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationOperation.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidationOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2008 IBM Corporation and others.
+ * Copyright (c) 2001, 2009 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,6 +17,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Queue;
 import java.util.Set;
 
 import org.eclipse.core.resources.IFile;
@@ -62,11 +63,12 @@
 import org.eclipse.wst.validation.internal.provisional.core.IValidatorJob;
 
 /**
- * Implemented Validators methods must not be called directly by anyone other than this class, since
+ * Validators must not be called directly by anyone other than this class, since
  * some initialization of the validator is done here (via the getProject() method). The
  * initialization is separated because the IProject isn't known until runtime.
  * <p>
  * This operation is not intended to be subclassed outside of the validation framework.
+ * </p>
  */
 public abstract class ValidationOperation implements IWorkspaceRunnable, IHeadlessRunnableWithProgress {
 	// Since IResourceConstants don't have a "no delta" flag, let this constant be the flag.
@@ -79,21 +81,49 @@
 	
 	protected static final boolean DEFAULT_FORCE = true;
 	
-	class ValidationLauncherJob extends Job {
-	    private Job validationJob;
-	    public ValidationLauncherJob(Job validationJob) {
+	private static ValidationLauncherJob launcherJob = new ValidationLauncherJob();
+	
+	private static final int jobsPerProcessor = 3;
+	
+	private final static class ValidationLauncherJob extends Job {
+	    private Queue<Job> _validationJobs = new LinkedList<Job>();
+	    
+	    public ValidationLauncherJob() {
             super(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_VALIDATION_JOB_MSG));
-            
             setSystem(true);
             setRule(ResourcesPlugin.getWorkspace().getRoot());
-            this.validationJob= validationJob;
 	    }
 	    
 	    protected IStatus run(IProgressMonitor monitor) {
-    		validationJob.schedule();
+			int processors = Runtime.getRuntime().availableProcessors();
+			int totalInitialJobs = processors * jobsPerProcessor;
+    		synchronized (_validationJobs) {
+    			// never schedule more than 3 validation jobs per processor at a time
+    			for (int i=0; i< totalInitialJobs; i++) {
+    				Job validationJob = _validationJobs.poll();
+    				if (validationJob == null) break;
+    				addJobChangeAdapter(validationJob);
+    				validationJob.schedule();
+    			}
+    		}
             return Status.OK_STATUS;
 	    }
 	    
+	    private void addJobChangeAdapter(Job job) {
+	    	job.addJobChangeListener(new JobChangeAdapter(){
+	    		// when done, see if there is another validation job to schedule
+				public void done(IJobChangeEvent event) {
+					synchronized (_validationJobs) {
+						Job validationJob = _validationJobs.poll();
+						if (validationJob != null) {
+							addJobChangeAdapter(validationJob);
+							validationJob.schedule();
+						}
+					}
+				}
+			});
+	    }
+	    
 	    @Override
 	    public boolean belongsTo(Object family) {
 			if (family == ResourcesPlugin.FAMILY_MANUAL_BUILD)return true;
@@ -102,6 +132,16 @@
 			}
 			return super.belongsTo(family);
 	    }
+	    
+	    public void addValidationJob(Job validationJob) {
+	    	synchronized (_validationJobs) {
+	    		_validationJobs.add(validationJob);
+	    		// schedule the job if we were empty
+	    		if (_validationJobs.size() == 1) {
+	    			this.schedule();
+	    		}
+	    	}
+	    }
 	}
 	
 	/**
@@ -1224,12 +1264,17 @@
 	 * (hProject.getName().indexOf("fork") > -1)) { Thread.dumpStack(); } System.err.println(prefix +
 	 * "End ValidationOperation"); }
 	 */
+	
+	/**
+	 * @deprecated This class is no longer used by the framework.
+	 */
 	public class ProjectRunnable implements Runnable {
 		private WorkbenchReporter _reporter;
 		private IValidator _validator;
 		private ValidatorMetaData _vmd;
 		private IFileDelta[] _delta;
 
+		@SuppressWarnings("unchecked")
 		public ProjectRunnable(WorkbenchReporter reporter, IValidator validator, 
 			ValidatorMetaData vmd, IWorkbenchContext helper, IFileDelta[] delta, Iterator iterator) {
 			_reporter = reporter;
@@ -1402,9 +1447,7 @@
 			}
 		);
 		validatorjob.setPriority(Job.DECORATE);
-
-		ValidationLauncherJob validationLauncherJob = new ValidationLauncherJob(validatorjob);
-		validationLauncherJob.schedule();
+		launcherJob.addValidationJob(validatorjob);
 	}
 		
 }
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidatorManager.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidatorManager.java
index 86bbbf3..7cf398b 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidatorManager.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/operations/ValidatorManager.java
@@ -121,15 +121,10 @@
 		try {
 			ProjectConfiguration prjp = ConfigurationManager.getManager().getProjectConfiguration(project);
 			prjp.setDoesProjectOverride(true);
-			ValidatorMetaData vmd = ValidationRegistryReader.getReader()
-					.getValidatorMetaData(validatorId);
+			ValidatorMetaData vmd = ValidationRegistryReader.getReader().getValidatorMetaData(validatorId);
 			
-			if(manualValidation){
-				prjp.disableSingleManualValidator(vmd);
-			} 
-			if (buildValidation){
-				prjp.disableSingleBuildValidator(vmd);
-			}
+			if(manualValidation)prjp.disableSingleManualValidator(vmd);
+			if (buildValidation)prjp.disableSingleBuildValidator(vmd);
 			prjp.store();
 			
 		} catch (InvocationTargetException e) {
diff --git a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/plugin/ValidationPlugin.java b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/plugin/ValidationPlugin.java
index f7f7d7b..2b8b8dd 100644
--- a/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/plugin/ValidationPlugin.java
+++ b/plugins/org.eclipse.wst.validation/validate/org/eclipse/wst/validation/internal/plugin/ValidationPlugin.java
@@ -10,20 +10,23 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal.plugin;
 
+import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResourceChangeEvent;
 import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ProjectScope;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Plugin;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
 import org.eclipse.wst.validation.ValidationFramework;
 import org.eclipse.wst.validation.internal.DependencyIndex;
 import org.eclipse.wst.validation.internal.EventManager;
 import org.eclipse.wst.validation.internal.ProjectUnavailableError;
 import org.eclipse.wst.validation.internal.ResourceUnavailableError;
 import org.eclipse.wst.validation.internal.Tracing;
-import org.eclipse.wst.validation.internal.ValOperationManager;
 import org.eclipse.wst.validation.internal.core.Message;
 import org.eclipse.wst.validation.internal.provisional.core.IMessage;
 import org.osgi.framework.Bundle;
@@ -100,15 +103,15 @@
 		DependencyIndex di = (DependencyIndex)ValidationFramework.getDefault().getDependencyIndex();
 		IWorkspace ws = ResourcesPlugin.getWorkspace();
 		ws.addSaveParticipant(this, di);
-		ws.addResourceChangeListener(ValOperationManager.getDefault(), 
-			IResourceChangeEvent.POST_BUILD | IResourceChangeEvent.PRE_BUILD);
+//		ws.addResourceChangeListener(ValOperationManager.getDefault(), 
+//			IResourceChangeEvent.POST_BUILD | IResourceChangeEvent.PRE_BUILD);
 
 	}
 
 	public void stop(BundleContext context) throws Exception {
 		super.stop(context);
 		ResourcesPlugin.getWorkspace().removeResourceChangeListener( EventManager.getManager() );		
-		ResourcesPlugin.getWorkspace().removeResourceChangeListener( ValOperationManager.getDefault() );		
+//		ResourcesPlugin.getWorkspace().removeResourceChangeListener( ValOperationManager.getDefault() );		
 		EventManager.getManager().shutdown();
 	}
 
@@ -121,6 +124,11 @@
 		return PLUGIN_ID;
 	}
 	
+	public static IEclipsePreferences getPreferences(IProject project){
+		IScopeContext projectContext = new ProjectScope(project);
+		return projectContext.getNode(PLUGIN_ID);
+	}
+	
 	/**
 	 * Write this exception to the log.
 	 * <p>
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/AbstractValidator.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/AbstractValidator.java
index 3d884d9..83c1d55 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/AbstractValidator.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/AbstractValidator.java
@@ -32,8 +32,10 @@
 	
 	/**
 	 * Validate the resource. The validator is called from a WorkspaceJob, so
-	 * the validator itself does not need to establish it's own
-	 * IWorkspaceRunnable.
+	 * the validator itself does not need to establish it's own IWorkspaceRunnable.
+	 * <p>
+	 * If you override this method then you should not override the other validate method.
+	 * </p>
 	 * 
 	 * @param resource
 	 * 		The resource to be validated.
@@ -56,7 +58,43 @@
 	 * 
 	 * @return the result of the validation. This may be, but usually isn't, null.
 	 */
-	public abstract ValidationResult validate(IResource resource, int kind, ValidationState state, IProgressMonitor monitor);
+	public ValidationResult validate(IResource resource, int kind, ValidationState state, IProgressMonitor monitor){
+		return null;
+	}
+	
+	/**
+	 * Validate the resource. The validator is called from a WorkspaceJob, so
+	 * the validator itself does not need to establish it's own
+	 * IWorkspaceRunnable.
+	 * <p>
+	 * If you override this method then you should not override the other
+	 * validate method.
+	 * </p>
+	 * 
+	 * @param event
+	 *            An object that describes the resource to be validated and why
+	 *            it should be validated.
+	 * 
+	 * @param state
+	 *            A way to pass arbitrary, validator specific, data from one
+	 *            invocation of a validator to the next, during the validation
+	 *            phase. At the end of the validation phase, this object will be
+	 *            cleared, thereby allowing any of this state information to be
+	 *            garbaged collected.
+	 * 
+	 * @param monitor
+	 *            A monitor that you can use to report your progress. To be a
+	 *            well behaved validator you need to check the isCancelled()
+	 *            method at appropriate times.
+	 * 
+	 * @return the result of the validation. Null should never be returned. If
+	 *         null is returned then the other validate method will be called as
+	 *         well.
+	 */
+	public ValidationResult validate(ValidationEvent event, ValidationState state, IProgressMonitor monitor){
+		return null;
+	}
+	
 	
 	/**
 	 * A call back method that lets the validator know that the project is being
@@ -122,6 +160,23 @@
 	 */
 	public void validationFinishing(IProject project, ValidationState state, IProgressMonitor monitor){		
 	}
+	
+	/**
+	 * Should the validation framework first clear the markers that this
+	 * validator has placed on this resource? This method can be overridden by
+	 * validator implementors to provide a validator specific behavior.
+	 * 
+	 * @param event
+	 *            The validation event that triggered the validation.
+	 * @return true if the validation framework should first clear all the
+	 *         markers that this validator produced. This is the default
+	 *         behavior. Return false to leave the markers unchanged. It then
+	 *         becomes the responsibility of the validator to manage it's own
+	 *         markers for this resource, for this validation event.
+	 */
+	public boolean shouldClearMarkers(ValidationEvent event){
+		return true;
+	}
 		
 	/**
 	 * Answer the validator that you belong to. The validator controls the
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Friend.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Friend.java
index 54f84d7..4146636 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Friend.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Friend.java
@@ -47,8 +47,11 @@
 	public static boolean shouldValidate(Validator validator, IResource resource, ValType valType, 
 		ContentTypeWrapper contentTypeWrapper){
 		
-		return validator.shouldValidate(resource, valType, contentTypeWrapper);
-		
+		return validator.shouldValidate(resource, valType, contentTypeWrapper);		
+	}
+	
+	public static void setMigrated(Validator validator, boolean migrated){
+		validator.setMigrated(migrated);
 	}
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/IMutableValidator.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/IMutableValidator.java
new file mode 100644
index 0000000..90ebfb1
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/IMutableValidator.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.validation;
+
+/**
+ * A validator that has fields that can be updated.
+ * <p>
+ * The following procedure is used to change a Validator's settings.
+ * <ol>
+ * <li>An IMutableValidator is retrieved.</li>
+ * <li>The IMutableValidator is changed.</li>
+ * <li>The IMutableValidator is "activated".</li>
+ * </ol>
+ * </p>
+ * <p>The methods {@link ValidationFramework#getProjectSettings(org.eclipse.core.resources.IProject)} and 
+ * {@link ValidationFramework#getWorkspaceSettings()} can be used to retrieve IMutableValidator's.
+ * <p>
+ * <b>Provisional API:</b> This class/interface is part of an interim API that is still under development and expected to 
+ * change significantly before reaching stability. It is being made available at this early stage to solicit feedback 
+ * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken 
+ * (repeatedly) as the API evolves.
+ * </p>
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+
+ * @author karasiuk
+ *
+ */
+public interface IMutableValidator {
+	
+	/**
+	 * Answer the validator's id.
+	 */
+	String getId();
+	
+	/**
+	 * Answer the validator's name.
+	 */
+	String getName();
+	
+	/**
+	 * Answer the validator's class name.
+	 * @return
+	 */
+	String getValidatorClassname();
+	
+	/**
+	 * Answer if the validator is enabled for build based validation.
+	 */
+	boolean isBuildValidation();
+	
+	/**
+	 * Answer if the validator is enabled for manual based validation.
+	 */
+	boolean isManualValidation();
+	
+	/**
+	 * Set whether the validator should be enabled for build based validation.
+	 */
+	void setBuildValidation(boolean build);
+	
+	/**
+	 * Set whether the validator should be enabled for manual based validation.
+	 */	
+	void setManualValidation(boolean manual);
+
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/IPerformanceMonitor.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/IPerformanceMonitor.java
index fe7c15b..b951270 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/IPerformanceMonitor.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/IPerformanceMonitor.java
@@ -20,7 +20,8 @@
  * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken 
  * (repeatedly) as the API evolves.
  * </p>
- * @noimplement
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
  * @author karasiuk
  *
  */
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/MutableProjectSettings.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/MutableProjectSettings.java
new file mode 100644
index 0000000..73bf21c
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/MutableProjectSettings.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.validation;
+
+import org.eclipse.core.resources.IProject;
+
+/**
+ * This class holds the overall project validation settings.
+ * <p>
+ * The following procedure is used to change a project's Validation settings.
+ * <ol>
+ * <li>The MutableProjectSettings are retrieved.</li>
+ * <li>The MutableProjectSettings are changed.</li>
+ * <li>The MutableProjectSettings are "applied".</li>
+ * </ol>
+ * </p>
+ * <p>In order for a project's validation setting to be effective, both 
+ * {@link #getOverride()} and {@link MutableWorkspaceSettings#getOverride()}
+ * must be true.
+ * </p>
+ * <p>
+ * These settings can be retrieved with {@link ValidationFramework#getProjectSettings(IProject)}.
+ * </p>
+ * <p>
+ * <b>Provisional API:</b> This class/interface is part of an interim API that is still under development and expected to 
+ * change significantly before reaching stability. It is being made available at this early stage to solicit feedback 
+ * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken 
+ * (repeatedly) as the API evolves.
+ * </p>
+
+ * @author karasiuk
+ *
+ */
+public final class MutableProjectSettings {
+	private final IProject	_project;
+
+	private boolean _override;
+	private boolean	_suspend;
+	private final IMutableValidator[] _validators;
+	
+	public IMutableValidator[] getValidators() {
+		return _validators;
+	}
+
+	public MutableProjectSettings(IProject project, IMutableValidator[] validators){
+		_project = project;
+		_validators = validators;
+	}
+
+	/**
+	 * Can this project override the workspace level validation settings?
+	 */
+	public boolean getOverride() {
+		return _override;
+	}
+
+	/**
+	 * Change whether this project can override workspace level validation settings.
+	 * @param override Set to true if the project is allowed to override workspace level validation settings.
+	 */
+	public void setOverride(boolean override) {
+		_override = override;
+	}
+
+	/**
+	 * Is validation suspended for this project?
+	 */
+	public boolean getSuspend() {
+		return _suspend;
+	}
+
+	/**
+	 * Change whether this project is suspending it's validation.
+	 * @param suspend Set to true, to suspend validation for this project.
+	 */
+	public void setSuspend(boolean suspend) {
+		_suspend = suspend;
+	}
+
+	/**
+	 * Answer the project that these settings are for.
+	 */
+	public IProject getProject() {
+		return _project;
+	}
+
+
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/MutableWorkspaceSettings.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/MutableWorkspaceSettings.java
new file mode 100644
index 0000000..80d18f1
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/MutableWorkspaceSettings.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.validation;
+
+import org.eclipse.wst.validation.internal.model.GlobalPreferencesValues;
+
+
+/**
+ * This class holds the overall workspace validation settings.
+ * <p>
+ * The following procedure is used to change a project's Validation settings.
+ * <ol>
+ * <li>The MutableWorkspaceSettings are retrieved.</li>
+ * <li>The MutableWorkspaceSettings are changed.</li>
+ * <li>The MutableWorkspaceSettings are "applied".</li>
+ * </ol>
+ * </p>
+ * <p>
+ * These settings can be retrieved with {@link ValidationFramework#getWorkspaceSettings()}.
+ * </p>
+ * <p>
+ * <b>Provisional API:</b> This class/interface is part of an interim API that is still under development and expected to 
+ * change significantly before reaching stability. It is being made available at this early stage to solicit feedback 
+ * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken 
+ * (repeatedly) as the API evolves.
+ * </p>
+
+ * @author karasiuk
+ *
+ */
+public final class MutableWorkspaceSettings {
+
+	private final GlobalPreferencesValues _values;
+	
+	private final IMutableValidator[] _validators;
+	
+	public IMutableValidator[] getValidators() {
+		return _validators;
+	}
+
+	public MutableWorkspaceSettings(IMutableValidator[] validators, GlobalPreferencesValues values){
+		_validators = validators;
+		_values = values;
+	}
+	
+	public GlobalPreferencesValues getGlobalPreferencesValues(){
+		return _values;
+	}
+	
+	public boolean getAutoSave() {
+		return _values.saveAutomatically;
+	}
+
+	public void setAutoSave(boolean autoSave) {
+		_values.saveAutomatically = autoSave;
+	}
+
+	/**
+	 * Can this project override the workspace level validation settings?
+	 */
+	public boolean getOverride() {
+		return _values.override;
+	}
+
+	/**
+	 * Change whether this project can override workspace level validation settings.
+	 * @param override Set to true if the project is allowed to override workspace level validation settings.
+	 */
+	public void setOverride(boolean override) {
+		_values.override = override;
+	}
+
+	/**
+	 * Is validation suspended for this project?
+	 */
+	public boolean getSuspend() {
+		return _values.disableAllValidation;
+	}
+
+	/**
+	 * Change whether this project is suspending it's validation.
+	 * @param suspend Set to true, to suspend validation for this project.
+	 */
+	public void setSuspend(boolean suspend) {
+		_values.disableAllValidation = suspend;
+	}
+
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationEvent.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationEvent.java
new file mode 100644
index 0000000..528e58e
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationEvent.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.validation;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+
+/**
+ * An object that describes which object should be validated and what triggered its validation.
+ * <p>
+ * <b>Provisional API:</b> This class/interface is part of an interim API that is still under development and expected to 
+ * change significantly before reaching stability. It is being made available at this early stage to solicit feedback 
+ * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken 
+ * (repeatedly) as the API evolves.
+ * </p>
+ * @author karasiuk
+ *
+ */
+
+public final class ValidationEvent {
+	
+	private IResource 		_resource;
+	private int				_kind;
+	private IResourceDelta 	_dependsOn;
+	
+	/**
+	 * Create an object that describes what should be validated.
+	 * 
+	 * @param resource
+	 *            The resource to be validated.
+	 * @param kind
+	 *            The way the resource changed. It uses the same values as the
+	 *            kind parameter in IResourceDelta.
+	 * @param dependsOn
+	 *            If the resource is being validated because one of it's
+	 *            dependencies has changed, that change is described here. This
+	 *            can be null.
+	 */
+	public ValidationEvent(IResource resource, int kind, IResourceDelta dependsOn){
+		_resource = resource;
+		_kind = kind;
+		_dependsOn = dependsOn;
+	}
+
+	/**
+	 * The resource to be validated.
+	 */
+	public IResource getResource() {
+		return _resource;
+	}
+
+	/**
+	 * The way the resource changed. It uses the same values as the kind
+	 * parameter in IResourceDelta.
+	 */
+	public int getKind() {
+		return _kind;
+	}
+
+	/**
+	 * If the resource is being validated because one of it's dependencies has changed, that change is described here.
+	 * This method will return null when the trigger is not because of a dependency change.
+	 */
+	public IResourceDelta getDependsOn() {
+		return _dependsOn;
+	}
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationFramework.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationFramework.java
index fe62b40..17cc455 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationFramework.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationFramework.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.wst.validation;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -18,6 +19,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceVisitor;
@@ -29,19 +31,32 @@
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.wst.validation.Validator.V1;
+import org.eclipse.wst.validation.internal.ConfigurationManager;
 import org.eclipse.wst.validation.internal.ContentTypeWrapper;
 import org.eclipse.wst.validation.internal.DebugConstants;
 import org.eclipse.wst.validation.internal.DependencyIndex;
 import org.eclipse.wst.validation.internal.DisabledResourceManager;
 import org.eclipse.wst.validation.internal.DisabledValidatorManager;
+import org.eclipse.wst.validation.internal.GlobalConfiguration;
 import org.eclipse.wst.validation.internal.MarkerManager;
 import org.eclipse.wst.validation.internal.Misc;
 import org.eclipse.wst.validation.internal.PerformanceMonitor;
+import org.eclipse.wst.validation.internal.ProjectUnavailableError;
 import org.eclipse.wst.validation.internal.ValManager;
 import org.eclipse.wst.validation.internal.ValOperation;
+import org.eclipse.wst.validation.internal.ValPrefManagerGlobal;
+import org.eclipse.wst.validation.internal.ValPrefManagerProject;
 import org.eclipse.wst.validation.internal.ValType;
 import org.eclipse.wst.validation.internal.ValidationRunner;
+import org.eclipse.wst.validation.internal.ValidatorMetaData;
+import org.eclipse.wst.validation.internal.ValidatorMutable;
+import org.eclipse.wst.validation.internal.ValManager.UseProjectPreferences;
+import org.eclipse.wst.validation.internal.model.GlobalPreferences;
+import org.eclipse.wst.validation.internal.model.GlobalPreferencesValues;
+import org.eclipse.wst.validation.internal.model.ProjectPreferences;
 import org.eclipse.wst.validation.internal.operations.ValidationBuilder;
+import org.eclipse.wst.validation.internal.operations.ValidatorManager;
 import org.eclipse.wst.validation.internal.operations.WorkbenchReporter;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 import org.eclipse.wst.validation.internal.provisional.core.IReporter;
@@ -62,25 +77,33 @@
  */
 public final class ValidationFramework {
 	
-	private IDependencyIndex 			_dependencyIndex;
+	private volatile IDependencyIndex 	_dependencyIndex;
 	private IPerformanceMonitor			_performanceMonitor;
 	
 	private Set<IProject> 				_suspendedProjects;
 	private boolean 					_suspendAllValidation;
 
-	private static ValidationFramework 	_me;
-	
 	/** 
 	 * Answer the singleton, default instance of this class.
 	 */
 	public static ValidationFramework getDefault(){
-		if (_me == null)_me = new ValidationFramework();
-		return _me;
+		return Singleton.vf;
 	}
 	
 	private ValidationFramework(){}
 	
 	/**
+	 * Add the validation builder to the project, so that the project can support
+	 * build time validation. It is safe to call this method, if the builder was
+	 * previously added to the project. It will not be added more than once.
+	 * 
+	 * @param project The project that the builder is added to.
+	 */
+	public void addValidationBuilder(IProject project){
+		ValidatorManager.addProjectBuildValidationSupport(project);
+	}
+	
+	/**
 	 * Clear any validation markers that may have been set by this validator.
 	 * 
 	 * @param resource
@@ -131,15 +154,15 @@
 	 * other resources.
 	 */
 	public IDependencyIndex getDependencyIndex(){
-		if (_dependencyIndex != null)return _dependencyIndex;
-		return getDependencyIndex2();
-	}
-
-	private synchronized IDependencyIndex getDependencyIndex2() {
-		if (_dependencyIndex == null)_dependencyIndex = new DependencyIndex();
+		// note how the _dependencyIndex is volatile so that this double checking approach can be used.
+		if (_dependencyIndex == null){
+			synchronized(this){
+				if (_dependencyIndex == null)_dependencyIndex = new DependencyIndex();
+			}
+		}
 		return _dependencyIndex;
 	}
-	
+
 	/**
 	 * Answer a performance monitor for the validators.
 	 */
@@ -155,7 +178,7 @@
 	}
 	
 	/**
-	 * Answer the preference store that holds the global validation settings.
+	 * Answer the preference store that holds the persisted global validation settings.
 	 */
 	public IEclipsePreferences getPreferenceStore(){
 		return new InstanceScope().getNode(ValidationPlugin.PLUGIN_ID);
@@ -254,6 +277,112 @@
 	}
 	
 	/**
+	 * Answer copies of all the registered validators.
+	 * 
+	 * @return Answer an empty array if there are no validators.
+	 */
+	public Validator[] getValidators(){
+		return ValManager.getDefault().getValidatorsCopy();
+	}
+		
+	/**
+	 * Answer the validation settings that have been defined on the
+	 * project. To "activate" any changes to these settings, the
+	 * {@link #applyChanges(MutableProjectSettings, boolean)} method needs to be
+	 * called.
+	 * 
+	 * @param project The project who's settings you wish to examine or change.
+	 * @return Validation settings that apply to the given project.
+	 */
+	public MutableProjectSettings getProjectSettings(IProject project){
+		ProjectPreferences pp = ValManager.getDefault().getProjectPreferences(project);
+		Validator[] vals = pp.getValidators();
+		ValidatorMutable[] vms = new ValidatorMutable[vals.length];
+		for (int i=0; i<vals.length; i++)vms[i] = new ValidatorMutable(vals[i]);
+
+		MutableProjectSettings mps = new MutableProjectSettings(project, vms);
+		mps.setOverride(pp.getOverride());
+		mps.setSuspend(pp.getSuspend());
+		return mps;
+	}
+	
+	/**
+	 * Answer the validation settings that have been defined at the workspace level.
+	 * To "activate" any changes to these settings, the
+	 * {@link #applyChanges(MutableWorkspaceSettings, boolean)} method needs to be
+	 * called.
+	 * 
+	 * @return Validation settings that apply to the entire workspace.
+	 */
+	public MutableWorkspaceSettings getWorkspaceSettings() throws InvocationTargetException{
+		
+		ValManager vm = ValManager.getDefault();
+		GlobalPreferences gp = vm.getGlobalPreferences();
+		
+		Validator[] vals = vm.getValidators();		
+		ValidatorMutable[] vms = new ValidatorMutable[vals.length];
+		for (int i=0; i<vals.length; i++)vms[i] = new ValidatorMutable(vals[i]);
+
+		MutableWorkspaceSettings mws = new MutableWorkspaceSettings(vms, gp.asValues());
+		return mws;
+	}
+		
+	/**
+	 * Apply the changes that have been been to the validation settings.
+	 * 
+	 * @param settings
+	 *            The project settings.
+	 * @param persist
+	 *            If true then the changes are persisted to the property files.
+	 *            If false the changes are applied to the validators, but are
+	 *            not persisted.
+	 */
+	public void applyChanges(MutableProjectSettings settings, boolean persist){
+		ValPrefManagerProject vpm = new ValPrefManagerProject(settings.getProject());
+		vpm.savePreferences(settings, persist);
+	}
+	
+	/**
+	 * Apply the changes that have been been to the validation settings.
+	 * 
+	 * @param settings
+	 *            The workspace settings.
+	 * @param persist
+	 *            If true then the changes are persisted to the property files.
+	 *            If false the changes are applied to the validators, but are
+	 *            not persisted.
+	 */
+	public void applyChanges(MutableWorkspaceSettings settings, boolean persist){
+		
+		ValManager vm = ValManager.getDefault();
+		GlobalPreferencesValues gpv = settings.getGlobalPreferencesValues();
+		vm.replace(gpv);
+		
+		IMutableValidator[] mvs = settings.getValidators();
+		ValidatorMutable[] vals = new ValidatorMutable[mvs.length];
+		for (int i=0; i<mvs.length; i++)vals[i] = (ValidatorMutable)mvs[i];
+		ValPrefManagerGlobal.getDefault().savePreferences(vm.getGlobalPreferences(), vals, persist);
+		ValPrefManagerGlobal.saveV1Preferences(vals, persist);		
+	}
+	
+	/**
+	 * Validators can use project level settings (Project natures and facets) to
+	 * determine if they are applicable to the project or not.
+	 * 
+	 * @param project
+	 *            The project that the configuration is based on.
+	 * @return The copies of the validators that are configured to run on this project based
+	 *         on the project level settings.
+	 * @throws ProjectUnavailableError
+	 */
+	public Validator[] getValidatorsConfiguredForProject(IProject project) throws ProjectUnavailableError {
+		Validator[] orig = ValManager.getDefault().getValidatorsConfiguredForProject(project, UseProjectPreferences.Normal);
+		Validator[] copy = new Validator[orig.length];
+		for (int i=0; i<orig.length; i++)copy[i] = orig[i].copy();
+		return copy;
+	}
+	
+	/**
 	 * Answer all the validators that are applicable for the given resource.
 	 * 
 	 * @param resource the resource that determines which validators are applicable.
@@ -288,6 +417,21 @@
 	}
 	
 	/**
+	 * Answer whether or not the validator has been activated, i.e. has the
+	 * bundle that defines the validator been loaded. We do not want to cause
+	 * unnecessary bundle loading, so this check can be performed by third party
+	 * callers, to prevent making other calls that will force the validator to
+	 * be loaded.
+	 * 
+	 * @param validator
+	 *            The validator that is being tested.
+	 * @return true if the validator has already been loaded.
+	 */
+	public boolean isLoaded(Validator validator){
+		return validator.isLoaded();
+	}
+	
+	/**
 	 * Waits until all validation jobs are finished. This method will block the
 	 * calling thread until all such jobs have finished executing, or until this
 	 * thread is interrupted. If there are no validation jobs that are
@@ -350,6 +494,55 @@
 		if (_suspendedProjects == null)_suspendedProjects = Collections.synchronizedSet(new HashSet<IProject>(20));
 		return _suspendedProjects;
 	}
+	
+	/**
+	 * Save the validators settings into the persistent store, there by making their settings the active settings.
+	 * <p>
+	 * A common use of this method would be to change whether particular validators are enabled or not. For example
+	 * if you only wanted the JSP validator enabled, you could use code similar to this:
+	 * <pre>
+	 * ValidationFramework vf = ValidationFramework.getDefault();
+	 * Validator[] vals = vf.getValidators();
+	 * for (Validator v : vals){
+	 *   boolean enabled = false;
+	 *   if (v.getValidatorClassname().equals("org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator"))enabled = true;
+	 *     v.setBuildValidation(enabled);
+	 *     v.setManualValidation(enabled);
+	 *  }
+	 * vf.saveValidators(vals);
+	 * </pre>
+	 * </p> 
+	 * 
+	 * @param validators The validators that you are saving.
+	 * 
+	 * @throws InvocationTargetException
+	 */
+	public void saveValidators(Validator[] validators) throws InvocationTargetException{
+		
+		
+		ValPrefManagerGlobal gp = ValPrefManagerGlobal.getDefault();
+		gp.saveAsPrefs(validators);	
+		
+		GlobalConfiguration gc = ConfigurationManager.getManager().getGlobalConfiguration();
+		
+		List<ValidatorMetaData> manual = new LinkedList<ValidatorMetaData>();
+		List<ValidatorMetaData> build = new LinkedList<ValidatorMetaData>();
+		for (Validator v : validators){
+			V1 v1 = v.asV1Validator();
+			if (v1 == null)continue;
+			if (v1.isManualValidation())manual.add(v1.getVmd());
+			if (v1.isBuildValidation())build.add(v1.getVmd());
+		}
+		
+		ValidatorMetaData[] array = new ValidatorMetaData[manual.size()];
+		gc.setEnabledManualValidators(manual.toArray(array));
+		
+		array = new ValidatorMetaData[build.size()];
+		gc.setEnabledBuildValidators(build.toArray(array));
+
+		gc.passivate();
+		gc.store();		
+	}
 
 	/**
 	 * Suspends, or undoes the suspension of, validation on all projects in the
@@ -424,7 +617,21 @@
 		ValOperation vo = ValidationRunner.validate(createMap(projects), type, monitor, true);
 		return vo.getResults();
 	}
-	
+
+	/**
+	 * Validate a specific file resource.
+	 * 
+	 * @param file
+	 *            The file to be validated.
+	 * @param monitor
+	 *            Progress monitor.
+	 * @return the result of validating the file.
+	 */
+  public ValidationResults validate(IFile file, IProgressMonitor monitor) throws CoreException{
+      ValOperation vo = ValidationRunner.validate(file, ValType.Manual, monitor, true);
+      return vo.getResults();
+    }
+	  
 	/**
 	 * Answer all the resources in the projects as a map.
 	 * @param projects
@@ -461,5 +668,16 @@
 		}
 		
 	}
+	
+	/**
+	 * Store the singleton for the ValidationFramework. This approach is used to avoid having to synchronize the
+	 * ValidationFramework.getDefault() method.
+	 * 
+	 * @author karasiuk
+	 *
+	 */
+	private static class Singleton {
+		static ValidationFramework vf = new ValidationFramework();
+	}
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResult.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResult.java
index 1e54b7c..c1714e1 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResult.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResult.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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
@@ -34,9 +34,9 @@
  */
 public final class ValidationResult {
 	
-	private List<ValidatorMessage> _messages;
+	private final List<ValidatorMessage> _messages = new LinkedList<ValidatorMessage>();
 	
-	private static ValidatorMessage[] _noMessages = new ValidatorMessage[0];
+	private final static ValidatorMessage[] _noMessages = new ValidatorMessage[0];
 	
 	private boolean		_canceled;
 	
@@ -78,12 +78,14 @@
 	 * one type of message, and those messages can be either be directly used by
 	 * the caller, or automatically converted into IMarkers by the validation
 	 * framework.
+	 * </p>
 	 * <p>
 	 * To make matters even more complicated there is a third way to return
 	 * messages. To make it easier for old validators to port to the new
 	 * framework, they can continue to use an IReporter. If a validator calls
 	 * the getReporter() method then it is assumed by the framework that that is
 	 * the approach that they have chosen.
+	 * </p>
 	 * 
 	 * @see #getReporter(IProgressMonitor)
 	 * 
@@ -91,7 +93,7 @@
 	 * 		A validation message.
 	 */
 	public void add(ValidatorMessage message){
-		getMessageList().add(message);
+		_messages.add(message);
 	}
 	
 	/**
@@ -163,6 +165,19 @@
 		_messages.toArray(msgs);
 		return msgs;
 	}
+		
+	/**
+	 * Answer a copy of any validation messages that were added by the validator. The array is a new
+	 * array, and each message is a copy. 
+	 * @return an array is returned even if there are no messages.
+	 */
+	public synchronized ValidatorMessage[] getMessagesAsCopy(){
+		if (_messages == null)return _noMessages;
+		ValidatorMessage[] msgs = new ValidatorMessage[_messages.size()];
+		int i = 0;
+		for (ValidatorMessage msg : _messages)msgs[i++] = msg.asCopy();
+		return msgs;
+	}
 
 	/**
 	 * Update the resources that the validated resource depends on. This can be
@@ -179,11 +194,6 @@
 		_dependsOn = dependsOn;
 	}
 	
-	private List<ValidatorMessage> getMessageList(){
-		if (_messages == null)_messages = new LinkedList<ValidatorMessage>();
-		return _messages;
-	}
-
 	/**
 	 * @return All the resources that were validated as a side-effect of
 	 * 	validating the main resource, or null if none were.
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResults.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResults.java
index f614121..ba947f8 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResults.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationResults.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.wst.validation;
 
+
 /**
  * The combined results of validating multiple resources.
  * <p>
@@ -21,11 +22,26 @@
  * @author karasiuk
  *
  */
-public class ValidationResults {
-	private ValidationResult _result;
+public final class ValidationResults {
+	
+	private final ValidatorMessage[] _messages;
+	private final int 	_error;
+	private final int	_warn;
+	private final int	_info;
 	
 	public ValidationResults(ValidationResult result){
-		_result = result;
+		if (result == null){
+			_messages = new ValidatorMessage[0];
+			_error = 0;
+			_warn = 0;
+			_info = 0;
+		}
+		else {
+			_messages = result.getMessagesAsCopy();
+			_error = result.getSeverityError();
+			_warn = result.getSeverityWarning();
+			_info = result.getSeverityInfo();
+		}
 	}
 	
 	/**
@@ -33,32 +49,28 @@
 	 * @return an array is returned even if there are no messages.
 	 */
 	public ValidatorMessage[] getMessages(){
-		if (_result == null)return new ValidatorMessage[0];
-		return _result.getMessages();
+		return _messages;
 	}
 
 	/**
 	 * Answer the number of error messages that were generated as part of this validation operation.
 	 */
 	public int getSeverityError() {
-		if (_result == null)return 0;
-		return _result.getSeverityError();
+		return _error;
 	}
 
 	/**
 	 * Answer the number of informational messages that were generated as part of this validation operation.
 	 */
 	public int getSeverityInfo() {
-		if (_result == null)return 0;
-		return _result.getSeverityInfo();
+		return _info;
 	}
 	
 	/**
 	 * Answer the number of warning messages that were generated as part of this validation operation.
 	 */
 	public int getSeverityWarning() {
-		if (_result == null)return 0;
-		return _result.getSeverityWarning();
+		return _warn;
 	}
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationState.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationState.java
index 3c194ac..8097de4 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationState.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidationState.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007 IBM Corporation and others.
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -35,7 +35,7 @@
  * @author karasiuk
  *
  */
-public class ValidationState {
+public final class ValidationState {
 	
 	/**
 	 * This is a special id.
@@ -45,10 +45,16 @@
 	 * resource that actually changed, is placed into the ValidationState using
 	 * this id.
 	 * </p>
+	 * @deprecated This approach is not thread safe, the longer form of the AbstractValidator validate method should be used instead.
+	 * @see AbstractValidator#validate(ValidationEvent, ValidationState, org.eclipse.core.runtime.IProgressMonitor)
 	 */
 	public static final String TriggerResource = ValidationPlugin.PLUGIN_ID + ".Trigger"; //$NON-NLS-1$
 
-	private Map<String, Object> _map = new HashMap<String, Object>(50);
+	// I can't use a ConncurrentHashMap because some of the clients store nulls.
+	private final Map<String, Object> _map = new HashMap<String, Object>(50);
+	
+	public ValidationState(){
+	}
 	
 	/**
 	 * Save some state information.
@@ -62,7 +68,7 @@
 	 * 		validation framework doesn't do anything with this object except
 	 * 		pass it along during the validation process.
 	 */
-	public void put(String id, Object value){
+	public synchronized void put(String id, Object value){
 		_map.put(id, value);
 	}
 	
@@ -76,7 +82,7 @@
 	 * @return any arbitrary data that the validator might find useful,
 	 * 	including null.
 	 */
-	public Object get(String id){
+	public synchronized Object get(String id){
 		return _map.get(id);
 	}
 
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Validator.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Validator.java
index 2e65ba7..dcaea84 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Validator.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/Validator.java
@@ -17,6 +17,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IProject;
@@ -41,7 +42,6 @@
 import org.eclipse.wst.validation.internal.ValManager;
 import org.eclipse.wst.validation.internal.ValMessages;
 import org.eclipse.wst.validation.internal.ValOperation;
-import org.eclipse.wst.validation.internal.ValOperationManager;
 import org.eclipse.wst.validation.internal.ValPrefManagerGlobal;
 import org.eclipse.wst.validation.internal.ValPrefManagerProject;
 import org.eclipse.wst.validation.internal.ValType;
@@ -114,6 +114,17 @@
 	/** How many times has a message field in this validator been changed since it was created (or copied)? */
 	protected transient int _changeCountMessages;
 	
+	/** Has the validator been migrated from an earlier version in this session, but not yet saved? */
+	private boolean _migrated;
+	
+	public Validator(IProject project){
+		_project = project;
+	}
+		
+	void setMigrated(boolean migrated){
+		_migrated = migrated;
+	}
+	
 	/**
 	 * Create a new validator based on a abstract validator.
 	 * 
@@ -137,8 +148,7 @@
 	 *            means that you are a global validator.
 	 */
 	public static Validator create(ValidatorMetaData vmd, ValidationConfiguration config, IProject project){
-		V1 v1 = new V1(vmd, config);
-		v1._project = project;
+		V1 v1 = new V1(vmd, config, project);
 		return v1;
 	}
 	
@@ -163,14 +173,14 @@
 	 * @param project the project being built.
 	 * @param monitor the monitor that should be used for reporting progress if the clean takes a long time.
 	 */
-	public void clean(IProject project, IProgressMonitor monitor){
+	public void clean(IProject project, ValOperation operation, IProgressMonitor monitor){
 	}	
 	
 	/**
 	 * Compare yourself based on Validator name.
 	 */
 	public int compareTo(Validator validator) {
-			return getName().compareTo(validator.getName());			
+		return getName().compareTo(validator.getName());			
 	}
 	
 	/** Answer a deep copy of yourself. */
@@ -189,9 +199,9 @@
 		_manualValidation = v._manualValidation;
 		_markerId = v._markerId;
 		_messageSettings = v._messageSettings;
-		_project = v._project;
 		_sourceId = v._sourceId;
 		_version = v._version;
+		_migrated = v._migrated;
 		
 		if (includeChangeCounts){
 			_changeCountGlobal = v._changeCountGlobal;
@@ -200,6 +210,23 @@
 	}
 	
 	/**
+	 * Should the validation framework first clear the markers that this
+	 * validator has placed on this resource? This method can be overridden by
+	 * validator implementors to provide a validator specific behavior.
+	 * 
+	 * @param event
+	 *            The validation event that triggered the validation.
+	 * @return true if the validation framework should first clear all the
+	 *         markers that this validator produced. This is the default
+	 *         behavior. Return false to leave the markers unchanged. It then
+	 *         becomes the responsibility of the validator to manage it's own
+	 *         markers for this resource, for this validation event.
+	 */
+	public boolean shouldClearMarkers(ValidationEvent event){
+		return true;
+	}
+	
+	/**
 	 * Answer true if this validator, based on it's filters, should validate
 	 * this resource. This method does not check to see if global validation or
 	 * project validation has been suspended or not.
@@ -331,17 +358,49 @@
 		}
 		return result;
 	}
+	
 	/**
 	 * Validate the resource.
 	 * 
-	 * @param resource the resource to be validated
-	 * @param kind the kind of resource change, see IResourceDelta for values.
-	 * @param operation the operation that this validation is running under. This can be null.
-	 * @param monitor a way to report progress. This can be null.
+	 * @param resource
+	 *            The resource to be validated.
+	 * @param kind
+	 *            The kind of resource change, see IResourceDelta for values.
+	 * @param operation
+	 *            The operation that this validation is running under. This can
+	 *            be null.
+	 * @param monitor
+	 *            A way to report progress. This can be null.
 	 * 
-	 * @return the result of doing the validation, it can be, but usually isn't null.
+	 * @return the result of doing the validation, it can be, but usually isn't
+	 *         null.
 	 */
-	public abstract ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor);	
+	public abstract ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor);
+	
+	/**
+	 * Validate the resource.
+	 * 
+	 * @param resource
+	 *            The resource to be validated.
+	 * @param kind
+	 *            The kind of resource change, see IResourceDelta for values.
+	 * @param operation
+	 *            The operation that this validation is running under. This can
+	 *            be null.
+	 * @param monitor
+	 *            A way to report progress. This can be null.
+	 * @param event
+	 *            An event that describes in more detail what should be
+	 *            validated and why it should be validated. This can be null.
+	 * 
+	 * @return the result of doing the validation, it can be, but usually isn't
+	 *         null.
+	 */
+	public ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor, ValidationEvent event){
+		// The reason that the resource and kind are still specified, is that I didn't want to remove a public method in the service
+		// stream. 
+		return validate(resource, kind, operation, monitor);		
+	}
 
 	/**
 	 * This method will be called before any validation takes place. It allows validators to perform any
@@ -471,16 +530,20 @@
 	 * Set whether this validator should be triggered as part of a manual validation.
 	 * 
 	 * @param manualValidation
+	 * @return true if the setting changed.
 	 */
-	public void setManualValidation(boolean manualValidation) {
-		setManualValidation2(manualValidation);
+	public boolean setManualValidation(boolean manualValidation) {
+		return setManualValidation2(manualValidation);
 	}
 	
-	protected final void setManualValidation2(boolean manualValidation) {
+	protected final boolean setManualValidation2(boolean manualValidation) {
+		boolean changed = false;
 		if (_manualValidation != manualValidation){
 			bumpChangeCountGlobal();
+			changed = true;
 			_manualValidation = manualValidation;
 		}
+		return changed;
 	}
 
 	/**
@@ -491,10 +554,10 @@
 	}
 	
 	/**
-	 * Has the validator changed since it was last created or copied?
+	 * Has the validator changed since it was last created or copied? Or was it migrated from an earlier version. 
 	 */
 	public boolean isChanged(){
-		if (_changeCountGlobal > 0 || _changeCountMessages > 0)return true;
+		if (_changeCountGlobal > 0 || _changeCountMessages > 0 || _migrated)return true;
 		return false;
 	}
 	
@@ -509,16 +572,20 @@
 	 * Set whether this validator should be triggered by the build process.
 	 * 
 	 * @param buildValidation
+	 * @return true if the setting changed.
 	 */
-	public void setBuildValidation(boolean buildValidation) {
-		setBuildValidation2(buildValidation);
+	public boolean setBuildValidation(boolean buildValidation) {
+		return setBuildValidation2(buildValidation);
 	}
 	
-	protected final void setBuildValidation2(boolean buildValidation) {
+	protected final boolean setBuildValidation2(boolean buildValidation) {
+		boolean changed = false;
 		if (_buildValidation != buildValidation){
 			bumpChangeCountGlobal();
+			changed = true;
 			_buildValidation = buildValidation;
 		}
+		return changed;
 	}
 
 	/**
@@ -571,7 +638,8 @@
 	 * @param vmd
 	 * @param config this is used to set the global enablement options. In some case this can be null.
 	 */
-	public V1(ValidatorMetaData vmd, ValidationConfiguration config){
+	public V1(ValidatorMetaData vmd, ValidationConfiguration config, IProject project){
+		super(project);
 		_vmd = vmd;
 		if (config != null){
 			setBuildValidation(config.isBuildEnabled(vmd));
@@ -598,17 +666,9 @@
 	public V1 asV1Validator() {
 		return this;
 	}
-	
-	@Override
-	public void become(Validator val) {
-		super.become(val);
-		V1 v1 = val.asV1Validator();
-		if (v1 == null)throw new IllegalArgumentException("Internal error, the incoming validator must be a v1 validator"); //$NON-NLS-1$
-		_vmd = v1._vmd;
-	}
-		
+			
 	public Validator copy(boolean includeChangeCounts) {
-		V1 v = new V1Copy(_vmd, null);
+		V1 v = new V1Copy(_vmd, null, _project);
 		v.copyLocal(this, includeChangeCounts);
 				
 		return v;
@@ -642,15 +702,17 @@
 	}
 	
 	@Override
-	public void setBuildValidation(boolean buildValidation) {
-		super.setBuildValidation(buildValidation);
+	public boolean setBuildValidation(boolean buildValidation) {
+		boolean changed = super.setBuildValidation(buildValidation);
 		_vmd.setBuildValidation(buildValidation);
+		return changed;
 	}
 	
 	@Override
-	public void setManualValidation(boolean manualValidation) {
-		super.setManualValidation(manualValidation);
+	public boolean setManualValidation(boolean manualValidation) {
+		boolean changed = super.setManualValidation(manualValidation);
 		_vmd.setManualValidation(manualValidation);
+		return changed;
 	}
 
 	@Override
@@ -709,28 +771,21 @@
 	 * want to copy the vmd object), I came up with this approach to only copy the fields that
 	 * the preference page was worried about. 
 	 */
-	public static class V1Copy extends V1 {
-		public V1Copy(ValidatorMetaData vmd, ValidationConfiguration vc){
-			super(vmd, vc);
+	public final static class V1Copy extends V1 {
+		public V1Copy(ValidatorMetaData vmd, ValidationConfiguration vc, IProject project){
+			super(vmd, vc, project);
 		}
 		
 		@Override
-		public void setManualValidation(boolean bool) {
-			setManualValidation2(bool);
+		public boolean setManualValidation(boolean bool) {
+			return setManualValidation2(bool);
 		}
 		
 		@Override
-		public void setBuildValidation(boolean bool) {
-			setBuildValidation2(bool);
+		public boolean setBuildValidation(boolean bool) {
+			return setBuildValidation2(bool);
 		}
-		
-		@Override
-		public void become(Validator val) {
-			super.become(val);
-			super.setBuildValidation(val.isBuildValidation());
-			super.setManualValidation(val.isManualValidation());
-		}
-		
+				
 	}
 		
 }
@@ -776,11 +831,22 @@
 		
 	private Level _level;
 	
+	/**
+	 * Do we still need to invoke the validateStarting method for this validator, for the null project?
+	 * 
+	 * Because we do not want to activate a validator's plug-in too soon, we do not activate the validator
+	 * as a reaction to the global validation starting event. Instead we mark it pending, and wait until
+	 * we are sure that we have something to validate.
+	 * 
+	 * If this flag is true, it means that the validateStarting method still needs to be called for this validator.
+	 */
+	private AtomicBoolean _pendingValidationStarted = new AtomicBoolean();
+	
 	V2(IConfigurationElement configElement, IProject project){
+		super(project);
 		assert configElement != null;
 		_validatorConfigElement = configElement;
 		_validatorClassName = configElement.getAttribute(ExtensionConstants.AttribClass);
-		_project = project;
 
 		IConfigurationElement[] groupReferenceElements = configElement.getChildren(ExtensionConstants.Group.elementGroup);
 		List<String> validatorGroupIDs = new ArrayList<String>();
@@ -794,9 +860,9 @@
 	}
 	
 	private V2(IProject project, String validatorClassName, AbstractValidator validator){
+		super(project);
 		assert validator != null;
 		
-		_project = project;
 		_validatorClassName = validatorClassName;
 		_validator = validator;
 		init();
@@ -828,6 +894,7 @@
 		return super.asIValidator();
 	}
 	
+	@Override
 	public V2 asV2Validator() {
 		return this;
 	}
@@ -837,11 +904,14 @@
 	 * 
 	 * @param project the project that is being cleaned. This can be null which means that the workspace
 	 * is being cleaned (in which case a separate call will be made for each open project).
+	 * 
 	 */
-	public void clean(IProject project, IProgressMonitor monitor) {
-		getDelegatedValidator().clean(project, ValOperationManager.getDefault().getOperation().getState(), monitor);
+	@Override
+	public void clean(IProject project, ValOperation operation, IProgressMonitor monitor) {
+		getDelegatedValidator().clean(project, operation.getState(), monitor);
 	}
 	
+	@Override
 	public Validator copy(boolean includeChangeCounts) {
 		V2 v = null;
 		if (_validatorConfigElement != null)v = new V2(_validatorConfigElement, _project);
@@ -853,13 +923,14 @@
 		FilterGroup[] groups = getGroups();
 		v._groupsArray = new FilterGroup[groups.length];
 		for (int i=0; i<groups.length; i++){
-			v._groupsArray[i] = groups[i].copy();
-			v._groups.add(v._groupsArray[i]);
+			v._groupsArray[i] = groups[i];
+			v._groups.add(groups[i]);
 		}
 
 		v._id = _id;
 		v._name = _name;
 		v._validatorGroupIds = _validatorGroupIds;
+		v._pendingValidationStarted = _pendingValidationStarted;
 				
 		return v;
 	}
@@ -905,6 +976,7 @@
 		return delegated;
 	}
 		
+	@Override
 	public String getId() {
 		return _id;
 	}
@@ -923,6 +995,7 @@
 		return groups;
 	}
 	
+	@Override
 	public String getName() {
 		return _name;
 	}
@@ -946,6 +1019,7 @@
 		return _validator;
 	}
 	
+	@Override
 	public String getValidatorClassname(){
 		return _validatorClassName;
 	}
@@ -974,12 +1048,18 @@
 	boolean isLoaded() {
 		return _validator != null;
 	}
+	
+	@Override
+	public boolean shouldClearMarkers(ValidationEvent event) {
+		return getValidator().shouldClearMarkers(event);
+	}
 		
 	/**
 	 * Answer true if this validator, based on it's filters, should validate this resource.
 	 * 
 	 * @return true if the resource should be validated.
 	 */
+	@Override
 	protected boolean shouldValidate(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 		FilterGroup[] groups = getGroups();
 		IProject project = resource.getProject();
@@ -1017,12 +1097,19 @@
 	}
 	
 	@Override
-	public ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor) {
+	public ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor){
+		return validate(resource, kind, operation, monitor, null);
+	}
+	
+	@Override
+	public ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor, ValidationEvent event) {
 		ValidationResult vr = null;
 		if (operation == null)operation = new ValOperation();
 		if (monitor == null)monitor = new NullProgressMonitor();
 		try {
-			vr = getDelegatedValidator().validate(resource, kind, operation.getState(), monitor);
+			if (event == null)event = new ValidationEvent(resource, kind, null);
+			vr = getDelegatedValidator().validate(event, operation.getState(), monitor);
+			if (vr == null)vr = getDelegatedValidator().validate(resource, kind, operation.getState(), monitor);
 		}
 		catch (Exception e){
 			try {
@@ -1071,7 +1158,6 @@
 	 * @return true if the test passed
 	 */
 //	private boolean sanityTest(int numberofMessages, IResource resource) {
-//		//FIXME make this more general and configurable
 //		if (numberofMessages < 201)return true;
 //		
 //		String resName = ""; //$NON-NLS-1$
@@ -1147,12 +1233,22 @@
 	
 	@Override
 	public void validationStarting(IProject project, ValidationState state, IProgressMonitor monitor) {
-		getDelegatedValidator().validationStarting(project, state, monitor);
+		if (project == null)_pendingValidationStarted.set(true);
+		else {
+			AbstractValidator val = getDelegatedValidator();
+			if (_pendingValidationStarted.getAndSet(false)){
+				val.validationStarting(null, state, monitor);
+			}
+			val.validationStarting(project, state, monitor);
+		}
 	}
 	
 	@Override
 	public void validationFinishing(IProject project, ValidationState state, IProgressMonitor monitor) {
-		getDelegatedValidator().validationFinishing(project, state, monitor);
+		if (project == null){
+			if (!_pendingValidationStarted.getAndSet(false))getDelegatedValidator().validationFinishing(null, state, monitor);
+		}
+		else getDelegatedValidator().validationFinishing(project, state, monitor);
 	}
 
 	@SuppressWarnings("unchecked")
@@ -1182,21 +1278,9 @@
 		return true;
 	}
 	
-	@Override
-	public void become(Validator val) {
-		super.become(val);
-		V2 v2 = val.asV2Validator();
-		if (v2 == null)throw new IllegalArgumentException(ValMessages.Error20);
-		_changeCountGroups = v2._changeCountGroups;
-		_delegated = v2._delegated;
-		_groups = v2._groups;
-		_groupsArray = v2._groupsArray;
-		_id = v2._id;
-		_name = v2._name;
-		_validator = v2._validator;
-		_validatorConfigElement = v2._validatorConfigElement;
-		_validatorClassName = v2._validatorClassName;
-		_validatorGroupIds = v2._validatorGroupIds;
+	public synchronized void replaceFilterGroup(FilterGroup existing, FilterGroup merged) {
+		remove(existing);
+		add(merged);
 	}
 
 }
@@ -1212,22 +1296,6 @@
 	}
 }
 
-/**
- * Take the instance variables from the incoming validator and set them to yourself.
- * @param validator
- */
-public void become(Validator validator) {
-	_buildValidation = validator._buildValidation;
-	_delegatingId = validator._delegatingId;
-	_manualValidation = validator._manualValidation;
-	_markerId = validator._markerId;
-	_messageSettings = validator._messageSettings;
-	_project = validator._project;
-	_sourceId = validator._sourceId;
-	_version = validator._version;
-	_changeCountGlobal = validator._changeCountGlobal;
-	_changeCountMessages = validator._changeCountMessages;
-}
 
 void setMessages(Map<String, MessageSeveritySetting> map) {
 	_messageSettings = map;
@@ -1238,6 +1306,10 @@
 	return _changeCountGlobal;
 }
 
+public boolean hasGlobalChanges(){
+	return _migrated || _changeCountGlobal > 0;
+}
+
 public int getChangeCountMessages() {
 	return _changeCountMessages;
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidatorMessage.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidatorMessage.java
index 70bdd90..b8146dc 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidatorMessage.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/ValidatorMessage.java
@@ -45,7 +45,7 @@
 	public static final String ValidationId = "ValidationId"; //$NON-NLS-1$
 	
 	/** Associate some arbitrary attributes with a message. */
-	private Map<String, Object>	_map = new HashMap<String, Object>(5);
+	private final Map<String, Object>	_map = new HashMap<String, Object>(5);
 	
 	private IResource	_resource;
 	
@@ -73,6 +73,17 @@
 	private ValidatorMessage(){}
 	
 	/**
+	 * Answer a copy of yourself.
+	 */
+	public ValidatorMessage asCopy(){
+		ValidatorMessage msg = new ValidatorMessage();
+		msg._resource = _resource;
+		msg._type = _type;
+		msg._map.putAll(_map);
+		return msg;
+	}
+	
+	/**
 	 * Returns the attribute with the given name. The result is an instance of
 	 * one of the following classes: <code>String</code>, <code>Integer</code>,
 	 * or <code>Boolean</code>. Returns <code>null</code> if the attribute is
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DebugConstants.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DebugConstants.java
index 53a020d..a466241 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DebugConstants.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DebugConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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
@@ -39,5 +39,17 @@
 	 * For example, if you wanted more detail on the XML validator you would use org.eclipse.wst.xml.core.xml 
 	 */
 	String ExtraValDetail = ValidationPlugin.PLUGIN_ID+"/extraValDetail"; //$NON-NLS-1$
+	
+	/** 
+	 * filter/allExcept - If supplied, it is as if this is the only validator that gets defined via
+	 * the extension point. All the other validators are ignored.
+	 */
+	String FilterAllExcept = ValidationPlugin.PLUGIN_ID+"/filter/allExcept"; //$NON-NLS-1$
+	
+	/**
+	 * trace/level - The tracing level. If not supplied a default of zero is used. The higher the number the
+	 * more verbose the tracing.
+	 */
+	String TraceLevel = ValidationPlugin.PLUGIN_ID+"/trace/level"; //$NON-NLS-1$
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DependencyIndex.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DependencyIndex.java
index 6e4026e..ff29dca 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DependencyIndex.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DependencyIndex.java
@@ -76,6 +76,7 @@
 
 	public synchronized void add(String id, IResource dependent, IResource dependsOn) {
 		init();
+		if (dependsOn == null || dependent == null)return;
 		Depends d = getOrCreateDepends(dependent, dependsOn);
 		if (d.getValidators().add(id))_dirty = true;
 	}
@@ -83,7 +84,7 @@
 	private Depends getOrCreateDepends(IResource dependent, IResource dependsOn) {
 		Set<Depends> set = getSet(_dependents, dependent);
 		for (Depends d : set){
-			if (d.getDependsOn() == dependsOn)return d;
+			if (d.getDependsOn().equals(dependsOn)) return d;
 		}
 		Depends d = new Depends(dependent, dependsOn);
 		_dirty = true;
@@ -118,8 +119,8 @@
 			_dependents = new HashMap<IResource,Set<Depends>>(100);
 		}
 		else {
-			String errorMessage = "The following dependency could not be restored " + //$NON-NLS-1$
-				"because the following resource {0} could no longer be found."; //$NON-NLS-1$
+			String errorMessage = "The following dependency could not be restored " + 
+				"because the following resource {0} could no longer be found."; 
 			DataInputStream in = null;
 			try {
 				IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
@@ -137,9 +138,8 @@
 				for (int i=0; i<numDependsOn; i++){
 					String v = in.readUTF();
 					IResource dependsOn = root.findMember(v);
-					if (v == null){
+					if (dependsOn == null){
 						Tracing.log(NLS.bind(errorMessage, v));
-						continue;
 					}
 					int numDependents = in.readInt();
 					for (int j=0; j<numDependents; j++){
@@ -147,12 +147,11 @@
 						IResource dependent = root.findMember(v);
 						if (dependent == null){
 							Tracing.log(NLS.bind(errorMessage, v));
-							continue;
 						}
 						int numVal = in.readInt();
 						for (int k=0; k<numVal; k++){
 							String id = in.readUTF();
-							add(id, dependent, dependsOn);
+							if (dependent != null && dependsOn != null)add(id, dependent, dependsOn);
 						}
 					}					
 				}				
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledResourceManager.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledResourceManager.java
index 1b522fa..120180f 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledResourceManager.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledResourceManager.java
@@ -15,11 +15,8 @@
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ProjectScope;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.IScopeContext;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 import org.osgi.service.prefs.BackingStoreException;
 
@@ -31,11 +28,8 @@
  */
 public class DisabledResourceManager implements IProjectChangeListener {
 	
-	private static DisabledResourceManager _me;
-	
 	public static DisabledResourceManager getDefault(){
-		if (_me == null)_me = new DisabledResourceManager();
-		return _me;
+		return Singleton.disabledResourceManager;
 	}
 	
 	private Set<IResource> _disabled = new HashSet<IResource>(100);
@@ -66,12 +60,7 @@
 		save(copy, resource.getProject());
 		_disabled = copy;		
 	}
-	
-	private IEclipsePreferences getPreferences(IProject project){
-		IScopeContext projectContext = new ProjectScope(project);
-		return projectContext.getNode(ValidationPlugin.PLUGIN_ID);
-	}
-	
+		
 	private void save(Set<IResource> disabled, IProject project) {
 		Serializer ser = new Serializer(200);
 		for (IResource resource : disabled){
@@ -79,7 +68,7 @@
 				ser.put(resource.getProjectRelativePath().toPortableString());
 			}
 		}
-		IEclipsePreferences prefs = getPreferences(project);
+		PreferencesWrapper prefs = PreferencesWrapper.getPreferences(project, null);
 		prefs.put(PrefConstants.disabled, ser.toString());
 		try {
 			prefs.flush();
@@ -92,7 +81,7 @@
 	private void load(IProject project){
 		Set<IResource> copy = new HashSet<IResource>(_disabled.size()+10);
 		copy.addAll(_disabled);
-		IEclipsePreferences prefs = getPreferences(project);
+		PreferencesWrapper prefs = PreferencesWrapper.getPreferences(project, null);
 		String disabled = prefs.get(PrefConstants.disabled, ""); //$NON-NLS-1$
 		if (disabled.length() > 0){
 			Deserializer des = new Deserializer(disabled);
@@ -153,5 +142,17 @@
 		}
 		_disabled = copy;
 	}
+	
+	/**
+	 * Store the singleton for the DisabledResourceManager. This approach is used to avoid having to synchronize the
+	 * DisabledResourceManager.getDefault() method.
+	 * 
+	 * @author karasiuk
+	 *
+	 */
+	private static class Singleton {
+		static DisabledResourceManager disabledResourceManager = new DisabledResourceManager();
+	}
+
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledValidatorManager.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledValidatorManager.java
index 4afe15e..7505e88 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledValidatorManager.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/DisabledValidatorManager.java
@@ -5,6 +5,7 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
@@ -18,20 +19,15 @@
  * @author karasiuk
  *
  */
-public class DisabledValidatorManager implements IValChangedListener {
+public final class DisabledValidatorManager implements IValChangedListener {
 	
-	private static DisabledValidatorManager _me;
-	private static int _counter;
+	private static final AtomicInteger _counter = new AtomicInteger();
 	private static final int CacheSize = 5;
 	
-	private Map<IResource, LRUSet> _map = Collections.synchronizedMap(new HashMap<IResource, LRUSet>(5));
+	private final Map<IResource, LRUSet> _map = Collections.synchronizedMap(new HashMap<IResource, LRUSet>(5));
 	
 	public static DisabledValidatorManager getDefault(){
-		DisabledValidatorManager me = _me;
-		if (me != null)return me;
-		me = new DisabledValidatorManager();
-		_me = me;
-		return me;
+		return Singleton.disabledValidatorManager;
 	}
 	
 	private DisabledValidatorManager(){
@@ -48,7 +44,7 @@
 	public Set<Validator> getDisabledValidatorsFor(IResource resource) {
 		LRUSet set = _map.get(resource);
 		if (set != null){
-			set.counter = _counter++;
+			set.counter = _counter.getAndIncrement();
 			return set.validators;
 		}
 		
@@ -71,18 +67,18 @@
 			_map.remove(oldest);
 		}
 		LRUSet set = new LRUSet();
-		set.counter = _counter++;
+		set.counter = _counter.getAndIncrement();
 		set.validators = vset;
 		_map.put(resource, set);		
 	}
 
 
-	private static class LRUSet {
+	private final static class LRUSet {
 		int counter;
 		Set<Validator> validators;
 	}
 	
-	private static class DisabledValidationFinder implements IValidatorVisitor {
+	private final static class DisabledValidationFinder implements IValidatorVisitor {
 		
 		private Map<String, Validator> _validators;
 
@@ -112,5 +108,18 @@
 	public void validatorsForProjectChanged(IProject project, boolean configSettingChanged) {
 		_map.clear();
 	}
+	
+	
+	/**
+	 * Store the singleton for the DisabledValidatorManager. This approach is used to avoid having to synchronize the
+	 * DisabledValidatorManager.getDefault() method.
+	 * 
+	 * @author karasiuk
+	 *
+	 */
+	private final static class Singleton {
+		final static DisabledValidatorManager disabledValidatorManager = new DisabledValidatorManager();
+	}
+
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionConstants.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionConstants.java
index 9073cdb..e702471 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionConstants.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionConstants.java
@@ -98,6 +98,9 @@
 		
 		/** contentType - filter by content type. */
 		String contentType = "contentType"; //$NON-NLS-1$
+		
+		/** pattern - filter paths by regular expression. */
+		String pattern = "pattern"; //$NON-NLS-1$
 	}
 	
 	/** Rule attributes */
@@ -121,6 +124,9 @@
 		/** name - a file name. */
 		String name = "name"; //$NON-NLS-1$
 		
+		/** regex - a Java regular expression. */
+		String regex = "regex"; //$NON-NLS-1$
+		
 		/** 
 		 * type - the type of file to be matched:
 		 * <ul>
@@ -130,6 +136,9 @@
 		 * </ul>
 		 */
 		String fileType = "type"; //$NON-NLS-1$
+		
+		/** version - facet version expression. See the facet framework for the exact syntax of this expression. */
+		String version = "version"; //$NON-NLS-1$
 	}
 	
 	interface FileType {
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionValidators.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionValidators.java
index 5b74568..090f4af 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionValidators.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ExtensionValidators.java
@@ -12,6 +12,8 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
 import org.eclipse.core.resources.IProject;
@@ -23,29 +25,26 @@
  * @author karasiuk
  *
  */
-public class ExtensionValidators {
+public final class ExtensionValidators {
 	private static ExtensionValidators _me;
 	
 	/** All the registered validators. The key is the validator id and the value is the validator. */
-	private Map<String, Validator> _map;
+	private final Map<String, Validator> _map;
 	
 	public synchronized static ExtensionValidators instance(){
 		if (_me == null){
 			_me = new ExtensionValidators();
-			_me.load();
 		}
 		return _me;
 	}
 
-	private ExtensionValidators(){};
-	
-	private void load() {
+	private ExtensionValidators(){
 		_map = new HashMap<String, Validator>(100);
 		for (Validator v : ValidatorExtensionReader.getDefault().process()){
 			_map.put(v.getId(), v);
-		}
+		}		
 	}
-
+	
 	/**
 	 * Answer all the v2 validators that have been defined by the extension point. This is the real
 	 * map (not a copy).
@@ -81,19 +80,31 @@
 		Map<String, Validator> map = new HashMap<String, Validator>();
 		map.putAll(_map);
 		
+		for (Validator v : getV1Validators(project))map.put(v.getId(), v);
+		
+		return map;
+	}
+	
+	/**
+	 * Answer the v1 validators that have been defined just on this project.
+	 * @param project
+	 * @return
+	 */
+	List<Validator> getV1Validators(IProject project){
+		List<Validator> list = new LinkedList<Validator>();
 		try {
 			ProjectConfiguration pc = new ProjectConfiguration(project);
 			pc.resetToDefault();
 			for (ValidatorMetaData vmd : pc.getValidators()){
 				Validator v = Validator.create(vmd, pc, project);
-				map.put(v.getId(), v);
+				list.add(v);
 			}
 		}
 		catch (InvocationTargetException e){
 			ValidationPlugin.getPlugin().handleException(e);
 		}
 
-		return map;
+		return list;
 	}
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/MarkerManager.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/MarkerManager.java
index 03722be..5c61529 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/MarkerManager.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/MarkerManager.java
@@ -31,13 +31,10 @@
  */
 public class MarkerManager {
 	
-	private static MarkerManager _me;
-	
 	private Set<String> _markers = new HashSet<String>(50);
 	
 	public static MarkerManager getDefault(){
-		if (_me == null)_me = new MarkerManager();
-		return _me;
+		return Singleton.markerManager;
 	}
 	
 	private MarkerManager(){
@@ -60,7 +57,12 @@
 		
 		String id = validator.getMarkerId();
 		if (id != null){
-			resource.deleteMarkers(id, true, IResource.DEPTH_ZERO);
+			try {
+				resource.deleteMarkers(id, true, IResource.DEPTH_ZERO);
+			}
+			catch (CoreException e){
+				// Nothing that we can do. This is not worth logging.
+			}
 			return;
 		}
 				
@@ -109,8 +111,14 @@
 			for (IMarker marker : markers){
 				if (_markers.contains(marker.getType())){
 					long createTime = marker.getCreationTime();
-//					long diff = createTime - operationStartTime;
-					if (createTime < operationStartTime)marker.delete();
+					if (createTime < operationStartTime){
+						try {
+							marker.delete();
+						}
+						catch (CoreException e){
+							// eat it - there is nothing we can do about this.
+						}
+					}
 				}
 			}
 		}
@@ -172,5 +180,17 @@
 	public Set<String> getMarkers() {
 		return _markers;
 	}
+	
+	/**
+	 * Store the singleton for the MarkerManager. This approach is used to avoid having to synchronize the
+	 * MarkerManager.getDefault() method.
+	 * 
+	 * @author karasiuk
+	 *
+	 */
+	private static class Singleton {
+		static MarkerManager markerManager = new MarkerManager();
+	}
+
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Misc.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Misc.java
index bf9beeb..ceafc41 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Misc.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Misc.java
@@ -29,7 +29,7 @@
  * @author karasiuk
  *
  */
-public class Misc {
+public final class Misc {
 	
 	public static void close(InputStream in){
 		if (in == null)return;
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/PreferencesWrapper.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/PreferencesWrapper.java
new file mode 100644
index 0000000..0f3a5e7
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/PreferencesWrapper.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.validation.internal;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.wst.validation.ValidationFramework;
+import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+
+/**
+ * The subset of the IEclipsePreferences interface that the framework needs to
+ * be able to persist preferences.
+ * @author karasiuk
+ *
+ */
+public abstract class PreferencesWrapper {
+	
+	private static final WrapperManger _manager = new WrapperManger();
+	
+	/**
+	 * Answer the preferences for the project. If project is null answer the global preferences.
+	 * @param project
+	 * @param persistent if null the default preferences are returned, if True the persisted 
+	 * preferences are return and if False the transient preferences are returned.
+	 * @return
+	 */
+	public static PreferencesWrapper getPreferences(IProject project, Boolean persistent){
+		return _manager.get(project, persistent);
+	}
+		
+	/**
+	 * These are the names of the node entries.
+	 * @return
+	 * @throws BackingStoreException
+	 */
+	public abstract String[] childrenNames() throws BackingStoreException;
+	
+	public void flush() throws BackingStoreException {
+	}
+	
+	public abstract boolean getBoolean(String key, boolean def);
+	
+	public abstract String get(String key, String def);
+	
+	public abstract int getInt(String key, int def);
+	
+	public abstract long getLong(String key, long def);
+
+	public abstract String[] keys() throws BackingStoreException;
+
+	public boolean isPersistent(){
+		return false;
+	}
+
+	public boolean isTransient(){
+		return false;
+	}
+	
+	public abstract void put(String key, String value);
+	
+	public abstract void putBoolean(String key, boolean value);
+	
+	public abstract void putLong(String key, long value);
+	
+	public abstract void putInt(String key, int value);
+	
+	/**
+	 * Unlike the more sophisticated org.osgi.service.prefs.Preferences support, 
+	 * this is currently limited to simple node names.
+	 */
+	public abstract PreferencesWrapper node(String nodeName);
+	
+	public abstract boolean nodeExists();
+	
+	public abstract boolean nodeExists(String pathName)  throws BackingStoreException;
+	
+	public abstract void removeNode()  throws BackingStoreException;
+
+
+public final static class PreferencesWrapperPersistent extends PreferencesWrapper {
+	
+	private final Preferences _preferences;
+	
+	public PreferencesWrapperPersistent(Preferences preferences){
+		_preferences = preferences;
+	}
+	
+	@Override
+	public String[] childrenNames() throws BackingStoreException {
+		return _preferences.childrenNames();
+	}
+	
+	public void flush() throws BackingStoreException {
+		_preferences.flush();
+	}
+	
+	@Override
+	public String get(String key, String def) {
+		return _preferences.get(key, def);
+	}
+	
+	@Override
+	public boolean getBoolean(String key, boolean def) {
+		return _preferences.getBoolean(key, def);
+	}
+	
+	@Override
+	public int getInt(String key, int def) {
+		return _preferences.getInt(key, def);
+	}
+	
+	@Override
+	public long getLong(String key, long def) {
+		return _preferences.getLong(key, def);
+	}
+	
+	@Override
+	public String[] keys() throws BackingStoreException {
+		return _preferences.keys();
+	}
+	
+	@Override
+	public boolean isPersistent() {
+		return true;
+	}
+	
+	@Override
+	public void put(String key, String value) {
+		_preferences.put(key, value);
+	}
+	
+	@Override
+	public PreferencesWrapper node(String path) {
+		Preferences prefs = _preferences.node(path);
+		return new PreferencesWrapperPersistent(prefs);
+	}
+	
+	@Override
+	public boolean nodeExists() {
+		try {
+			return nodeExists(""); //$NON-NLS-1$
+		}
+		catch (BackingStoreException e){
+		
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean nodeExists(String pathName) throws BackingStoreException  {
+		return _preferences.nodeExists(pathName);
+	}
+	
+	public void putBoolean(String key, boolean value) {
+		_preferences.putBoolean(key, value);	
+	}
+	
+	public void putLong(String key, long value){
+		_preferences.putLong(key, value);
+	}
+	
+	@Override
+	public void putInt(String key, int value) {
+		_preferences.putInt(key, value);
+	}
+	
+	@Override
+	public void removeNode() throws BackingStoreException {
+		_preferences.removeNode();
+	}
+}
+
+public final static class PreferencesWrapperTransient extends PreferencesWrapper {
+	
+	private final PreferencesWrapperTransient _parent;
+	private final Map<String, String> _children = Collections.synchronizedMap(new HashMap<String, String>(10));
+	private final Map<String, PreferencesWrapperTransient> _nodes = Collections.synchronizedMap(new HashMap<String, PreferencesWrapperTransient>(10));
+	
+	public PreferencesWrapperTransient(PreferencesWrapperTransient parent){
+		_parent = parent;
+	}
+	
+	public PreferencesWrapperTransient(PreferencesWrapper pw, PreferencesWrapperTransient parent) {
+		_parent = parent;
+		try {
+			for (String key : pw.keys()){
+				put(key, pw.get(key, null));
+			}
+			
+			
+			for (String nodeName : pw.childrenNames()){
+				PreferencesWrapper p = pw.node(nodeName);
+				PreferencesWrapperTransient pwt = new PreferencesWrapperTransient(p, this);
+				_nodes.put(nodeName, pwt);
+			}
+		}
+		catch (BackingStoreException e){
+			
+		}
+	}
+
+	@Override
+	public String[] childrenNames() throws BackingStoreException {
+		Set<String> keys = _nodes.keySet();
+		String names[] = new String[keys.size()];
+		keys.toArray(names);
+		return names;
+	}
+	
+	@Override
+	public String get(String key, String def) {
+		String value = _children.get(key);
+		if (value != null)return value;
+		return def;
+	}
+	
+	@Override
+	public boolean getBoolean(String key, boolean def) {
+		String value = _children.get(key);
+		if (value == null)return def;
+		value = value.toLowerCase();
+		if ("true".equals(value))return true; //$NON-NLS-1$
+		if ("false".equals(value))return false; //$NON-NLS-1$
+		return def;
+	}
+	
+	@Override
+	public int getInt(String key, int def) {
+		String value = _children.get(key);
+		if (value == null)return def;
+		try {
+			return Integer.parseInt(value);
+		}
+		catch (NumberFormatException e){
+		}
+		return def;
+	}
+	
+	@Override
+	public long getLong(String key, long def) {
+		String value = _children.get(key);
+		if (value == null)return def;
+		try {
+			return Long.parseLong(value);
+		}
+		catch (NumberFormatException e){
+		}
+		return def;
+	}
+	
+	@Override
+	public boolean isTransient() {
+		return true;
+	}
+	
+	@Override
+	public synchronized String[] keys() throws BackingStoreException {
+		String[] keys = new String[_children.size()];
+		_children.keySet().toArray(keys);
+		return keys;
+	}
+	
+	@Override
+	public synchronized PreferencesWrapper node(String name) {
+		PreferencesWrapperTransient pw  = _nodes.get(name);
+		if (pw != null)return pw;
+		pw = new PreferencesWrapperTransient(this);
+		_nodes.put(name, pw);
+		return pw;
+	}
+	
+	@Override
+	public boolean nodeExists() {
+		return true;
+	}
+	
+	@Override
+	public boolean nodeExists(String key) throws BackingStoreException {
+		PreferencesWrapperTransient pw = _nodes.get(key);
+		if (pw != null)return true;
+		return false;
+	}
+	
+	@Override
+	public void put(String key, String value) {
+		_children.put(key, value);
+	}
+	
+	@Override
+	public void putBoolean(String key, boolean bool) {
+		String value = bool ? "true" : "false";  //$NON-NLS-1$//$NON-NLS-2$
+		_children.put(key, value);
+	}
+	
+	@Override
+	public void putInt(String key, int value) {
+		_children.put(key, String.valueOf(value));
+	}
+	
+	@Override
+	public void putLong(String key, long value) {
+		_children.put(key, String.valueOf(value));
+	}
+	
+	@Override
+	public void removeNode() throws BackingStoreException {
+		if (_parent == null)return;
+		_parent.removeNode(this);
+	}
+	
+	private synchronized void removeNode(PreferencesWrapperTransient node){
+		String key = null;
+		for (Map.Entry<String, PreferencesWrapperTransient> me : _nodes.entrySet()){
+			if (me.getValue().equals(node)){
+				key = me.getKey();
+				break;
+			}
+		}
+		if (key != null)_nodes.remove(key);
+	}
+}
+
+private final static class WrapperManger implements IProjectChangeListener {
+	
+	private final Map<IProject, PreferencesWrapper> _map = new HashMap<IProject, PreferencesWrapper>(20); 
+	private final AtomicReference<PreferencesWrapper> _global = new AtomicReference<PreferencesWrapper>();
+	
+	private WrapperManger(){
+		EventManager.getManager().addProjectChangeListener(this);
+	}
+	
+	/**
+	 * Currently this object never goes away, but if that was ever to change then we would need to dispose it.
+	 */
+	@Override
+	protected void finalize() throws Throwable {
+		dispose();
+	}
+	
+	public void dispose(){
+		EventManager.getManager().removeProjectChangeListener(this);
+	}
+
+	public PreferencesWrapper get(IProject project, Boolean persistent) {
+		if (project == null)return globalPreferences(persistent);
+		PreferencesWrapper pw = null;
+		synchronized(_map){
+			pw = _map.get(project);
+		}
+		
+		if (pw != null && (persistent == null || persistent == pw.isPersistent()))return pw;
+		
+		if (pw == null)pw = new PreferencesWrapperPersistent(ValidationPlugin.getPreferences(project));
+		if (persistent != null && persistent && pw.isTransient())pw = new PreferencesWrapperPersistent(ValidationPlugin.getPreferences(project));
+		if (persistent != null && !persistent && pw.isPersistent())pw = new PreferencesWrapperTransient(pw, null);
+		
+		synchronized(_map){
+			_map.put(project, pw);
+		}
+		
+		return pw;
+	}
+
+	/**
+		 * Answer the appropriate global preferences.
+		 * 
+		 * @param persistent
+		 *            If null then answer the current saved global preferences,
+		 *            creating a new persistent one if there is none. If True,
+		 *            then ensure that the preferences are persistent. If False,
+		 *            ensure that the preferences are transient.
+		 * @return
+		 */
+	private PreferencesWrapper globalPreferences(Boolean persistent) {
+		PreferencesWrapper pw = _global.get();
+		
+		while(pw == null){
+			PreferencesWrapper newPW = createGlobal(persistent);
+			if (_global.compareAndSet(null, newPW))pw = newPW;
+			else pw = _global.get();
+		}
+		
+		while (persistent != null && !persistent && !pw.isTransient()){
+			PreferencesWrapper newPW = new PreferencesWrapperTransient(pw, null);
+			if (_global.compareAndSet(pw, newPW))pw = newPW;
+			else pw = _global.get();
+		}
+		
+		while (persistent != null && persistent && !pw.isPersistent()){
+			PreferencesWrapper newPW = new PreferencesWrapperPersistent(ValidationFramework.getDefault().getPreferenceStore());
+			if (_global.compareAndSet(pw, newPW))pw = newPW;
+			else pw = _global.get();			
+		}
+		return pw;
+	}
+	
+	private PreferencesWrapper createGlobal(Boolean persistent){
+		PreferencesWrapper pw = new PreferencesWrapperPersistent(ValidationFramework.getDefault().getPreferenceStore());
+		if (persistent == null || persistent)return pw;
+		return new PreferencesWrapperTransient(pw, null);
+	}
+
+	public void projectChanged(IProject project, int type) {
+		int interested = IProjectChangeListener.ProjectClosed | IProjectChangeListener.ProjectDeleted;
+		if ((type & interested) != 0){
+			synchronized (_map) {
+				_map.remove(project);
+			}
+		}
+		
+	}
+	
+}
+
+
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Tracing.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Tracing.java
index cb7dded..77e49cb 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Tracing.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/Tracing.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * Copyright (c) 2005, 2009 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
@@ -14,6 +14,9 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 
@@ -22,41 +25,73 @@
  * @author karasiuk
  *
  */
-public class Tracing {
+public final class Tracing {
 	
-	private static DateFormat 	_df = new SimpleDateFormat("HH:mm:ss.SSSS"); //$NON-NLS-1$
-	private static boolean		_forceLogging;
-	private static Boolean		_traceMatches;
-	private static Boolean		_traceV1;
-	private static String		_extraValDetail;
+	private final static DateFormat _df = new SimpleDateFormat("HH:mm:ss.SSSS"); //$NON-NLS-1$
+	private final static boolean	_isLogging = ValidationPlugin.getPlugin().isDebugging();
+	private final static boolean	_traceMatches = Misc.debugOptionAsBoolean(DebugConstants.TraceMatches);
+	private final static boolean	_traceV1 = Misc.debugOptionAsBoolean(DebugConstants.TraceV1);
+	private final static String		_extraValDetail = Platform.getDebugOption(DebugConstants.ExtraValDetail);
+	private final static int 		_tracingLevel;
+	
+	private final static String		_filter = Platform.getDebugOption(DebugConstants.FilterAllExcept);
+	
+	static {
+		String traceLevel = Platform.getDebugOption(DebugConstants.TraceLevel);
+		int level = 0;
+		if (traceLevel != null){
+			try {
+				level = Integer.parseInt(traceLevel);
+			}
+			catch (Exception e){
+			}
+		}
+		_tracingLevel = level;
+	}
+	
+	/**
+	 * Answer true if the filters allow this validator to be enabled. Normally this method will answer true.
+	 * It is only when filters are activated via the debugging options, that this method might return false.
+	 * This is used to aid in debugging by making it look like only one validator has been registered.
+	 * 
+	 * @param validatorId the validator id.
+	 * @return true if the validator should be registered via an extension point.
+	 */
+	public static boolean isEnabled(String validatorId){
+		if (_filter == null || _filter.length() == 0)return true;
+		return (_filter.equals(validatorId));		
+	}
 	
 	/**
 	 * Are we in logging/debugging mode?
 	 */
 	public static boolean isLogging(){
-		return _forceLogging || ValidationPlugin.getPlugin().isDebugging();
+		return _isLogging;
+	}
+	
+	/**
+	 * Answer true if we are in logging mode, and if the current logging level is greater than or
+	 * equal to level.
+	 * @param level The logging level that we are testing. The higher the level the more verbose
+	 * the tracing.
+	 */
+	public static boolean isLogging(int level){
+		if (_isLogging){
+			return _tracingLevel >= level;
+		}
+		return false;
 	}
 	
 	public static boolean isTraceMatches(){
-		if (_traceMatches == null){
-			_traceMatches = Misc.debugOptionAsBoolean(DebugConstants.TraceMatches);
-		}
 		return _traceMatches;
 	}
 	
 	public static boolean isTraceV1(){
-		if (_traceV1 == null){
-			_traceV1 = Misc.debugOptionAsBoolean(DebugConstants.TraceV1);
-		}
 		return _traceV1;
 	}
 	
 	public static boolean matchesExtraDetail(String validatorId){
-		if (_extraValDetail == null){
-			_extraValDetail = Platform.getDebugOption(DebugConstants.ExtraValDetail);
-			if (_extraValDetail == null)_extraValDetail = ""; //$NON-NLS-1$
-		}
-		if (_extraValDetail.length() == 0)return false;
+		if (_extraValDetail == null)return false;
 		return _extraValDetail.equals(validatorId);
 	}
 
@@ -86,7 +121,7 @@
 
 	public static String timestampIt(String line){
 		Date date = new Date();
-		long thread = Thread.currentThread().getId();
+		String thread = Thread.currentThread().getName();
 		return _df.format(date) + " " + thread + " " + line;  //$NON-NLS-1$//$NON-NLS-2$		
 	}
 
@@ -99,14 +134,75 @@
 	}
 
 	/**
-	 * Force the logging to be turned on. Normally logging is turned on via -debug options. However
-	 * the logging can be forced to be on by setting this to true. (Setting this to false doesn't force
-	 * the logging to be turned off).
+	 * This method doesn't do anything, and will be removed.
 	 * 
-	 * @param forceLogging
+	 * @deprecated
 	 */
 	public static void setForceLogging(boolean forceLogging) {
-		_forceLogging = forceLogging;
+	}
+	
+	/**
+	 * Log up to maxNumber deltas to the log.
+	 * @param delta The deltas to log.
+	 * @param maxNumber The maximum number of deltas to log.
+	 */
+	public static void logResourceDeltas(IResourceDelta delta, int maxNumber){
+		if (!isLogging())return;
+		if (delta == null)Tracing.log("  ResourceDelta: null"); //$NON-NLS-1$
+		else {
+			DeltaLogger logger = new DeltaLogger(maxNumber);
+			try {
+				delta.accept(logger);
+				if (logger.getCount() == 0)Tracing.log("  ResourceDelta: no deltas"); //$NON-NLS-1$
+			}
+			catch (CoreException e){
+				// eat it
+			}
+		}
+	}
+	
+	/**
+	 * A debugging class that prints out some resource delta's.
+	 * @author karasiuk
+	 *
+	 */
+	private final static class DeltaLogger implements IResourceDeltaVisitor {
+		
+		private final int 	_max;
+		private int 		_count;
+		public int getCount() {
+			return _count;
+		}
+
+		private StringBuffer _b = new StringBuffer(200);
+		
+		public DeltaLogger(int max){
+			_max = max;
+		}
+
+		public boolean visit(IResourceDelta delta) throws CoreException {
+			if (_count++ > _max)return false;
+			int kind = delta.getKind();
+			String type = "unknown"; //$NON-NLS-1$
+			switch (kind){
+			case IResourceDelta.ADDED:
+				type = "Added"; //$NON-NLS-1$
+				break;
+			case IResourceDelta.CHANGED:
+				type = "Changed"; //$NON-NLS-1$
+				break;
+			case IResourceDelta.REMOVED:
+				type = "Removed"; //$NON-NLS-1$
+				break;				
+			}
+			_b.append("  ResourceDelta "); //$NON-NLS-1$
+			_b.append(type);
+			_b.append(' ');
+			_b.append(delta.getResource());
+			Tracing.log(_b);
+			return true;
+		}
+		
 	}
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValBuilderJob.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValBuilderJob.java
index 59c6c63..5aafeee 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValBuilderJob.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValBuilderJob.java
@@ -30,6 +30,7 @@
 import org.eclipse.wst.validation.DependentResource;
 import org.eclipse.wst.validation.Friend;
 import org.eclipse.wst.validation.IDependencyIndex;
+import org.eclipse.wst.validation.ValidationEvent;
 import org.eclipse.wst.validation.ValidationFramework;
 import org.eclipse.wst.validation.ValidationState;
 import org.eclipse.wst.validation.Validator;
@@ -43,27 +44,23 @@
  * <p>
  * This is the main class for supporting build based validation. When triggered it looks at all of the
  * resource changes and determines what needs to be validated. 
+ * </p>
  * @author karasiuk
  *
  */
-public class ValBuilderJob extends WorkspaceJob implements IResourceDeltaVisitor, IResourceVisitor {
+public final class ValBuilderJob extends WorkspaceJob {
 	
 	private static ValBuilderJob _job;
 	private static Queue<ValidationRequest> _work = new LinkedList<ValidationRequest>();
 	
-	/** The monitor to use while running the build. */
-	private IProgressMonitor	_monitor;
-	
-	private SubMonitor			_subMonitor;
-	
-	private ValidationRequest	_request;
-	
+	private final ValOperation _operation = new ValOperation();
+		
 	/** The types of changes we are interested in. */
 	private final static int	InterestedFlags = IResourceDelta.CONTENT | IResourceDelta.ENCODING |
 		IResourceDelta.MOVED_FROM | IResourceDelta.MOVED_TO;
 	
-	public static synchronized void validateProject(IProject project, IResourceDelta delta, int buildKind, ValOperation operation){
-		ValidationRequest request = new ValidationRequest(project, delta, buildKind, operation);
+	public static synchronized void validateProject(IProject project, IResourceDelta delta, int buildKind){
+		ValidationRequest request = new ValidationRequest(project, delta, buildKind);
 		if (_job == null){
 			_job = new ValBuilderJob();
 			_job.add(request);
@@ -106,6 +103,7 @@
 		_work.add(request);
 	}
 	
+	@Override
 	public boolean belongsTo(Object family) {
 		if (family == ResourcesPlugin.FAMILY_MANUAL_BUILD)return true;
 		if (family == ValidationBuilder.FAMILY_VALIDATION_JOB){
@@ -115,24 +113,55 @@
 		return super.belongsTo(family);
 	}
 
+	@Override
 	public IStatus runInWorkspace(IProgressMonitor monitor) {
 		Tracing.log("ValBuilderJob-01: Starting"); //$NON-NLS-1$
-		_monitor = monitor;
 		
-		ValidationRequest request = getRequest();
-		while(request != null){
-			_request = request;
-			run();
-			request = getRequest();
+		try {
+			startingValidation(monitor);
+			
+			ValidationRequest request = getRequest();
+			while(request != null){
+				run(request, monitor);
+				request = getRequest();
+			}
 		}
-		_request = null;
+		finally {
+			finishingValidation(monitor);
+		}
 		
 		Tracing.log("ValBuilderJob-02: Finished"); //$NON-NLS-1$
 		return Status.OK_STATUS;
 	}
+
+	private void startingValidation(IProgressMonitor monitor) {
+        IValidatorVisitor startingVisitor = new IValidatorVisitor(){
+
+            public void visit(Validator validator, IProject project, ValType valType, 
+                ValOperation operation, IProgressMonitor monitor) {
+                
+                validator.validationStarting(project, operation.getState(), monitor);                   
+            }               
+        };
+
+        ValManager.getDefault().accept(startingVisitor, null, ValType.Build, getOperation(), monitor);
+	}
 	
-	private void run(){
-		setName(ValMessages.JobName + " " + _request.getProject().getName()); //$NON-NLS-1$
+	private void finishingValidation(IProgressMonitor monitor) {
+		
+		IValidatorVisitor finishedVisitor = new IValidatorVisitor(){
+
+		    public void visit(Validator validator, IProject project, ValType valType,
+		      ValOperation operation, IProgressMonitor monitor) {
+
+		      validator.validationFinishing(project, operation.getState(), monitor);              
+		    }           
+		  };
+		  ValManager.getDefault().accept(finishedVisitor, null, ValType.Build, getOperation(), monitor);
+	}
+
+	private void run(ValidationRequest request, IProgressMonitor monitor){
+		setName(ValMessages.JobName + " " + request.getProject().getName()); //$NON-NLS-1$
 		try {		
 	        IValidatorVisitor startingVisitor = new IValidatorVisitor(){
 
@@ -143,10 +172,10 @@
 	            }               
 	        };
 
-	        ValManager.getDefault().accept(startingVisitor, _request.getProject(), ValType.Build, _request.getOperation(), _monitor);
+	        ValManager.getDefault().accept(startingVisitor, request.getProject(), ValType.Build, getOperation(), monitor);
 		  
-			if (_request.getDelta() == null)fullBuild();
-			else deltaBuild();
+			if (request.getDelta() == null)fullBuild(request, monitor);
+			else deltaBuild(request, monitor);
 
 			
 		}
@@ -168,74 +197,33 @@
 		      validator.validationFinishing(project, operation.getState(), monitor);              
 		    }           
 		  };
-          ValManager.getDefault().accept(finishedVisitor, _request.getProject(), ValType.Build, _request.getOperation(), _monitor);
+          ValManager.getDefault().accept(finishedVisitor, request.getProject(), ValType.Build, getOperation(), monitor);
 		}
 		
 	}
 
-	private void deltaBuild() throws CoreException {
+	private void deltaBuild(ValidationRequest request, IProgressMonitor monitor) throws CoreException {
 		ResourceCounter counter = new ResourceCounter();
-		_request.getDelta().accept(counter);
-		_subMonitor = SubMonitor.convert(_monitor, counter.getCount());
-		_request.getDelta().accept(this);		
+		request.getDelta().accept(counter);
+		SubMonitor subMonitor = SubMonitor.convert(monitor, counter.getCount());
+		Visitor vistitor = new Visitor(request, subMonitor, monitor, getOperation());
+		request.getDelta().accept(vistitor);		
 	}
 
-	private void fullBuild() throws CoreException {
+	private void fullBuild(ValidationRequest request, IProgressMonitor monitor) throws CoreException {
 		ResourceCounter counter = new ResourceCounter();
-		_request.getProject().accept(counter, 0);
-		_subMonitor = SubMonitor.convert(_monitor, counter.getCount());
-		_request.getProject().accept(this);
+		request.getProject().accept(counter, 0);
+		SubMonitor subMonitor = SubMonitor.convert(monitor, counter.getCount());
+		Visitor vistitor = new Visitor(request, subMonitor, monitor, getOperation());
+		request.getProject().accept(vistitor);
 		
 	}
-
-	public boolean visit(IResourceDelta delta) throws CoreException {
-		IResource resource = delta.getResource();
-		if (DisabledResourceManager.getDefault().isDisabled(resource)){
-			MarkerManager.getDefault().deleteMarkers(resource, _request.getOperation().getStarted(), IResource.DEPTH_INFINITE);
-			return false;
-		}
-		int kind = delta.getKind();
-		boolean isChanged = (kind & IResourceDelta.CHANGED) != 0;
-		if (isChanged &&  (delta.getFlags() & InterestedFlags) == 0)return true;
-		
-		if ((kind & (IResourceDelta.ADDED | IResourceDelta.CHANGED)) != 0){
-			ValManager.getDefault().validate(_request.getProject(), resource, delta.getKind(), ValType.Build, 
-				_request.getBuildKind(), _request.getOperation(), _subMonitor.newChild(1));
-		}
-				
-		IDependencyIndex index = ValidationFramework.getDefault().getDependencyIndex();
-		if (index.isDependedOn(resource)){
-			MarkerManager mm = MarkerManager.getDefault();
-			for (DependentResource dr : index.get(resource)){
-				if (Friend.shouldValidate(dr.getValidator(), dr.getResource(), ValType.Build, new ContentTypeWrapper())){
-					mm.clearMarker(dr.getResource(), dr.getValidator()); 
-					_request.getOperation().getState().put(ValidationState.TriggerResource, resource);
-					ValManager.getDefault().validate(dr.getValidator(), _request.getOperation(), dr.getResource(), 
-						IResourceDelta.NO_CHANGE, _monitor);
-				}
-			}
-		}
-				
-		return true;
-	}
-
-	public boolean visit(IResource resource) throws CoreException {
-		try {
-			if (DisabledResourceManager.getDefault().isDisabled(resource)){
-				MarkerManager.getDefault().deleteMarkers(resource, _request.getOperation().getStarted(), IResource.DEPTH_INFINITE);
-				return false;
-			}
-			ValManager.getDefault().validate(_request.getProject(), resource, IResourceDelta.NO_CHANGE, ValType.Build, 
-				_request.getBuildKind(), _request.getOperation(), _subMonitor.newChild(1));
-		}
-		catch (ResourceUnavailableError e){
-			if (Tracing.isLogging())Tracing.log("ValBuilderJob-02: " + e.toString()); //$NON-NLS-1$
-			return false;
-		}
-		return true;
-	}
 	
-	static class ResourceCounter implements IResourceProxyVisitor, IResourceDeltaVisitor {
+	private ValOperation getOperation(){
+		return _operation;
+	}
+
+	static final class ResourceCounter implements IResourceProxyVisitor, IResourceDeltaVisitor {
 		
 		private int _count;
 
@@ -254,27 +242,24 @@
 		}		
 	}
 	
-	static class ValidationRequest {
+	static final class ValidationRequest {
 		/** The project that is being built. */
-		private IProject 			_project;
+		private final IProject 			_project;
 		
 		/** The resource delta that triggered the build, it will be null for a full build. */
-		private IResourceDelta		_delta;
-		
-		private ValOperation		_operation;
+		private final IResourceDelta	_delta;
 		
 		/** 
 		 * The kind of build.
 		 * 
 		 *  @see org.eclipse.core.resources.IncrementalProjectBuilder
 		 */
-		private int					_buildKind;
+		private final int					_buildKind;
 		
-		public ValidationRequest(IProject project, IResourceDelta delta, int buildKind, ValOperation operation){
+		public ValidationRequest(IProject project, IResourceDelta delta, int buildKind){
 			_project = project;
 			_delta = delta;
 			_buildKind = buildKind;
-			_operation = operation;
 		}
 
 		public IProject getProject() {
@@ -285,13 +270,76 @@
 			return _delta;
 		}
 
-		public ValOperation getOperation() {
-			return _operation;
-		}
-
 		public int getBuildKind() {
 			return _buildKind;
 		}
 	}
+	
+	private final static class Visitor implements IResourceDeltaVisitor, IResourceVisitor{
+		
+		private final ValidationRequest 	_request;
+		private final SubMonitor 			_subMonitor;
+		private final IProgressMonitor 		_monitor;
+		private final ValOperation			_operation;
+		
+		public Visitor(ValidationRequest request, SubMonitor subMonitor, IProgressMonitor monitor, ValOperation operation){
+			_request = request;
+			_subMonitor = subMonitor;
+			_monitor = monitor;
+			_operation = operation;
+		}
+		
+		public boolean visit(IResource resource) throws CoreException {
+			try {
+				if (DisabledResourceManager.getDefault().isDisabled(resource)){
+					MarkerManager.getDefault().deleteMarkers(resource, _operation.getStarted(), IResource.DEPTH_INFINITE);
+					return false;
+				}
+				ValManager.getDefault().validate(_request.getProject(), resource, IResourceDelta.NO_CHANGE, ValType.Build, 
+					_request.getBuildKind(), _operation, _subMonitor.newChild(1));
+			}
+			catch (ResourceUnavailableError e){
+				if (Tracing.isLogging())Tracing.log("ValBuilderJob-02: " + e.toString()); //$NON-NLS-1$
+				return false;
+			}
+			return true;
+		}
+		
+		@SuppressWarnings("deprecation")
+		public boolean visit(IResourceDelta delta) throws CoreException {
+			IResource resource = delta.getResource();
+			if (DisabledResourceManager.getDefault().isDisabled(resource)){
+				MarkerManager.getDefault().deleteMarkers(resource, _operation.getStarted(), IResource.DEPTH_INFINITE);
+				return false;
+			}
+			int kind = delta.getKind();
+			boolean isChanged = (kind & IResourceDelta.CHANGED) != 0;
+			if (isChanged &&  (delta.getFlags() & InterestedFlags) == 0)return true;
+			
+			if ((kind & (IResourceDelta.ADDED | IResourceDelta.CHANGED)) != 0){
+				ValManager.getDefault().validate(_request.getProject(), resource, delta.getKind(), ValType.Build, 
+					_request.getBuildKind(), _operation, _subMonitor.newChild(1));
+			}
+					
+			IDependencyIndex index = ValidationFramework.getDefault().getDependencyIndex();
+			if (index.isDependedOn(resource)){
+				MarkerManager mm = MarkerManager.getDefault();
+				for (DependentResource dr : index.get(resource)){
+					Validator val = dr.getValidator();
+					if (Friend.shouldValidate(val, dr.getResource(), ValType.Build, new ContentTypeWrapper())){
+						_operation.getState().put(ValidationState.TriggerResource, resource);
+						ValidationEvent event = new ValidationEvent(dr.getResource(), IResourceDelta.NO_CHANGE, delta);
+						if (val.shouldClearMarkers(event))mm.clearMarker(dr.getResource(), val); 
+						ValManager.getDefault().validate(val, _operation, dr.getResource(), 
+							IResourceDelta.NO_CHANGE, _monitor, event);
+					}
+				}
+			}
+					
+			return true;
+		}
+
+		
+	}
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValManager.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValManager.java
index 9f64f59..3b2d041 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValManager.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValManager.java
@@ -20,6 +20,10 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
@@ -43,11 +47,13 @@
 import org.eclipse.wst.validation.IPerformanceMonitor;
 import org.eclipse.wst.validation.IValidatorGroupListener;
 import org.eclipse.wst.validation.PerformanceCounters;
+import org.eclipse.wst.validation.ValidationEvent;
 import org.eclipse.wst.validation.ValidationFramework;
 import org.eclipse.wst.validation.ValidationResult;
 import org.eclipse.wst.validation.ValidationState;
 import org.eclipse.wst.validation.Validator;
 import org.eclipse.wst.validation.internal.model.GlobalPreferences;
+import org.eclipse.wst.validation.internal.model.GlobalPreferencesValues;
 import org.eclipse.wst.validation.internal.model.IValidatorVisitor;
 import org.eclipse.wst.validation.internal.model.ProjectPreferences;
 import org.eclipse.wst.validation.internal.operations.ManualValidatorsOperation;
@@ -59,36 +65,34 @@
  * @author karasiuk
  *
  */
-public class ValManager implements IValChangedListener, IFacetedProjectListener, IProjectChangeListener {
+public final class ValManager implements IValChangedListener, IFacetedProjectListener, IProjectChangeListener {
 	
-	private static ValManager _me;
-		
 	/**
 	 * Projects may be allowed to override the global validation settings. If that is the case then those
 	 * project specific settings are saved here. If the key exists, but the value is null, then that
 	 * means that the project has been checked and it does not have any specific settings.
 	 */
-	private Map<IProject, ProjectPreferences> _projectPreferences = 
+	private final Map<IProject, ProjectPreferences> _projectPreferences = 
 		Collections.synchronizedMap(new HashMap<IProject, ProjectPreferences>(50));
 	
-	private GlobalPreferences _globalPreferences;
+	private final AtomicReference<GlobalPreferences> _globalPreferences = new AtomicReference<GlobalPreferences>();
 		
 	/**
 	 * This number increases each time any of the validation configurations change. It is used to determine
 	 * if information that we have cached in the ValProperty is stale or not. This starts off at zero, each time
 	 * the workbench is started.
 	 */
-	private int _configNumber;
-	private ValidatorIdManager _idManager = new ValidatorIdManager();
+	private final AtomicInteger _configNumber = new AtomicInteger();
 	
-	private ValidatorProjectManager _projectManager = new ValidatorProjectManager();
-	
+	private final ValidatorIdManager _idManager = new ValidatorIdManager();
+	private final ValidatorCache 	_cache = new ValidatorCache();
+		
 	private static final QualifiedName StatusBuild = new QualifiedName(ValidationPlugin.PLUGIN_ID, "sb"); //$NON-NLS-1$
 	private static final QualifiedName StatusManual = new QualifiedName(ValidationPlugin.PLUGIN_ID, "sm"); //$NON-NLS-1$
-			
-	public static synchronized ValManager getDefault(){
-		if (_me == null)_me = new ValManager();
-		return _me;
+
+	
+	public static ValManager getDefault(){
+		return Singleton.valManager;
 	}
 	
 	private ValManager(){
@@ -116,7 +120,7 @@
 	 * Because if you make changes to the original validators, and since we only save differences,
 	 * there won't be any differences. 
 	 * 
-	 * @return Answer an empty array if there are no validators.
+	 * @return Answer the validators in name sorted order. Answer an empty array if there are no validators.
 	 * 
 	 * @see #getValidatorsCopy()
 	 */
@@ -161,13 +165,38 @@
 	 *            project settings are used. Normal validation would set this to true.
 	 *            The properties page would set this to false.
 	 *            
-	 * @deprecated Use {@link #getValidators(IProject)} instead            
+	 * @deprecated Use {@link #getValidatorsNotCached(IProject)} instead            
 	 */
-	public synchronized Validator[] getValidators(IProject project, boolean respectOverrideSettings) throws ProjectUnavailableError {
+	public Validator[] getValidators(IProject project, boolean respectOverrideSettings) throws ProjectUnavailableError {
 		return getValidators(project);
 	}
 	
 	/**
+	 * Answer a cached copy of the the validators for a given project. This is a front end method, 
+	 * for the getValidatorsNotCached() method.
+	 * <p>
+	 * Individual projects may override the global validation preference
+	 * settings. If the project has it's own settings, then those validators are
+	 * returned via this method.
+	 * </p>
+	 * <p>
+	 * The following approach is used. For version 1 validators, the validator
+	 * is only returned if it is defined to operate on this project type. This
+	 * is the way that the previous version of the framework did it. For version
+	 * 2 validators, they are all returned.
+	 * </p>
+	 * 
+	 * @param project
+	 *            This may be null, in which case the global preferences are
+	 *            returned.
+	 * 
+	 * @return The validators in name sorted order.
+	 */
+	public Validator[] getValidators(IProject project) throws ProjectUnavailableError {
+		return _cache.getValidatorsCached(project);
+	}
+	
+	/**
 	 * Answer all the validators for the given project.
 	 * <p>
 	 * Individual projects may override the global validation preference
@@ -182,12 +211,15 @@
 	 * </p>
 	 * 
 	 * @param project
-	 *            This may be null, in which case the global preferences are returned.
+	 *            This may be null, in which case the global preferences are
+	 *            returned.
+	 * 
+	 * @return The validators in name sorted order.
 	 */
-	public synchronized Validator[] getValidators(IProject project) throws ProjectUnavailableError {
-		Map<String,Validator> v2Vals = getV2Validators(project);
+	private Validator[] getValidatorsNotCached(IProject project) throws ProjectUnavailableError {
+		Map<String,Validator> v2Vals = getV2Validators(project, UseProjectPreferences.Normal);
 		TreeSet<Validator> sorted = new TreeSet<Validator>();
-		for (Validator v : v2Vals.values())sorted.add(v);
+		sorted.addAll(v2Vals.values());
 		
 		try {
 			ValidationConfiguration vc = ConfigurationManager.getManager().getConfiguration(project);
@@ -216,31 +248,114 @@
 		sorted.toArray(vals);
 		return vals;
 	}
+	/**
+	 * Validators can use project level settings (Project natures and facets) to
+	 * determine if they are applicable to the project or not.
+	 * 
+	 * @param project
+	 *            The project that the configuration is based on.
+	 * @param mustUseProjectSettings
+	 *            Force the project properties to be used. There is a case where the user has toggled the
+	 *            Enable project specific settings checkbox in the dialog, but has not yet committed the
+	 *            changes. This allows that setting to be passed through.
+	 * @return The validators that are configured to run on this project based
+	 *         on the project level settings. These are the "live" validators, they are not copies.
+	 * @throws ProjectUnavailableError
+	 * 
+	 * @deprecated Use getValidatorsConfiguredForProject(IProject project, UseProjectPreferences useProject)
+	 */
+	public Validator[] getValidatorsConfiguredForProject(IProject project, boolean mustUseProjectSettings) throws ProjectUnavailableError {
+		UseProjectPreferences useProject = UseProjectPreferences.Normal;
+		return getValidatorsConfiguredForProject(project, useProject);
+	}
 	
 	/**
-	 * Answer the V2 validators that are in effect for this project. The following approach is used:
+	 * Validators can use project level settings (Project natures and facets) to
+	 * determine if they are applicable to the project or not.
+	 * 
+	 * @param project
+	 *            The project that the configuration is based on.
+	 * @param useProject
+	 *            Specifies how to use the project preferences. This can be used
+	 *            to force the project properties to be used. There is a case
+	 *            where the user has toggled the Enable project specific
+	 *            settings checkbox in the dialog, but has not yet committed the
+	 *            changes. This allows that setting to be passed through.
+	 * @return The validators that are configured to run on this project based
+	 *         on the project level settings. These are the "live" validators,
+	 *         they are not copies.
+	 * @throws ProjectUnavailableError
+	 */
+	public Validator[] getValidatorsConfiguredForProject(IProject project, UseProjectPreferences useProject) throws ProjectUnavailableError {
+		Map<String,Validator> v2Vals = getV2Validators(project, useProject);
+		TreeSet<Validator> sorted = new TreeSet<Validator>();
+		sorted.addAll(v2Vals.values());
+		
+		if (useProject == UseProjectPreferences.MustNotUse){
+			sorted.addAll(ExtensionValidators.instance().getV1Validators(project));
+		}
+		else {
+			try {
+				ValidationConfiguration vc = ConfigurationManager.getManager().getProjectConfiguration(project);
+				ValidatorMetaData[] vmds = vc.getValidators();
+				for (ValidatorMetaData vmd : vmds) {
+					Validator v = Validator.create(vmd, vc, project);
+					sorted.add(v);
+				}
+			}
+			catch (InvocationTargetException e){
+				ValidationPlugin.getPlugin().handleException(e);
+			}
+		}
+				
+		List<Validator> list = new LinkedList<Validator>();
+		for (Validator v : sorted){
+			if (v.shouldValidateProject(project, false, false))list.add(v);
+		}
+		
+		Validator[]vals = new Validator[list.size()];
+		list.toArray(vals);
+		return vals;
+	}
+	
+	/**
+	 * Answer the V2 validators that are in effect for this project. The
+	 * following approach is used:
 	 * <ol>
 	 * <li>The validators that are defined by the extension point are loaded.</li>
 	 * <li>They are customized by any global preferences.</li>
-	 * <li>If project customizations are allowed, they are customized by the project preferences.
+	 * <li>If project customizations are allowed, they are customized by the
+	 * project preferences.
 	 * </ol>
 	 * 
 	 * @param project
-	 *            This may be null, in which case only the global preferences are used.
+	 *            This may be null, in which case only the global preferences
+	 *            are used.
+	 * @param useProject
+	 *            Specifies how to use the project preferences. This can be used
+	 *            to force the project properties to be used. There is a case
+	 *            where the user has toggled the Enable project specific
+	 *            settings checkbox in the dialog, but has not yet committed the
+	 *            changes. This allows that setting to be passed through.
+	 *            
 	 * @return
 	 */
-	private Map<String,Validator> getV2Validators(IProject project){
+	private Map<String,Validator> getV2Validators(IProject project, UseProjectPreferences useProject){
 		Map<String,Validator> extVals = ExtensionValidators.instance().getMapV2Copy();
 		try {
 			List<Validator> vals = ValPrefManagerGlobal.getDefault().getValidators();
 			for (Validator v : vals)extVals.put(v.getId(), v);
 			
-			if (!mustUseGlobalValidators(project)){
-				//TODO should probably cache this vpm
-				ValPrefManagerProject vpm = new ValPrefManagerProject(project);
-				vals = vpm.getValidators(extVals);
-				for (Validator v : vals)extVals.put(v.getId(), v);
-			}		
+			if (useProject != UseProjectPreferences.MustNotUse){
+				if (useProject == UseProjectPreferences.MustUse || !mustUseGlobalValidators(project)){
+					//TODO should probably cache this vpm
+					ValPrefManagerProject vpm = new ValPrefManagerProject(project);
+					vals = vpm.getValidators(extVals);
+					for (Validator v : vals)extVals.put(v.getId(), v);
+					
+					for (Validator v : getProjectPreferences(project).getValidators())extVals.put(v.getId(), v);
+				}	
+			}
 		}
 		catch (BackingStoreException e){
 			ValidationPlugin.getPlugin().handleException(e);
@@ -259,14 +374,11 @@
 	public boolean mustUseGlobalValidators(IProject project){
 		if (project == null)return true;
 		if (!getGlobalPreferences().getOverride())return true;
-		ProjectPreferences pp = getProjectPreferences2(project);
-		if (pp == null){
-			ValPrefManagerProject vpm = new ValPrefManagerProject(project);
-			pp = new ProjectPreferences(project); 
-			vpm.loadProjectPreferencesShallow(pp);
-		}
+		ProjectPreferences pp = _projectPreferences.get(project);
+		if (pp != null)return !pp.getOverride();
 		
-		return !pp.getOverride();
+		ValPrefManagerProject vpm = new ValPrefManagerProject(project);
+		return !vpm.getOverride();
 	}
 	
 	/**
@@ -336,7 +448,7 @@
 		GlobalPreferences gp = getGlobalPreferences();
 		if (!gp.getOverride() || project == null)return gp.getDisableAllValidation();
 		
-		ProjectPreferences pp = getProjectPreferences2(project);
+		ProjectPreferences pp = _projectPreferences.get(project);
 		if (pp == null)return gp.getDisableAllValidation();
 		return pp.getSuspend();		
 	}
@@ -427,26 +539,46 @@
 	 * This method needs to be called whenever the validation configuration has changed.
 	 */
 	private void configHasChanged(){
-		_configNumber++;
-		_projectManager.reset();
+		_configNumber.incrementAndGet();
+		ValidatorProjectManager.reset();
+		_cache.reset();
 	}
 		
 	/**
 	 * Answer the global validation preferences.
 	 */
-	public synchronized GlobalPreferences getGlobalPreferences(){
-		GlobalPreferences gp = _globalPreferences;
+	public GlobalPreferences getGlobalPreferences(){
+		GlobalPreferences gp = _globalPreferences.get();
 		if (gp == null){
 			ValPrefManagerGlobal vpm = ValPrefManagerGlobal.getDefault();
-			gp = new GlobalPreferences();
-			vpm.loadGlobalPreferences(gp);
-			_globalPreferences = gp;
+			gp = vpm.loadGlobalPreferences();
+			if (!_globalPreferences.compareAndSet(null, gp))gp = _globalPreferences.get();
 		}
-		return gp;		
+		return gp;
 	}
 	
+	/**
+	 * Update the global preferences, but only if something has actually changed.
+	 * @param values The global settings.
+	 * @return a bit mask of the changes between the old values and the new values. See the GlobalPreferences
+	 * constants for the bit mask values. If a zero is return there were no changes.
+	 */
+	public int replace(GlobalPreferencesValues values){
+		GlobalPreferences gp = new GlobalPreferences(values);
+		GlobalPreferences old = getGlobalPreferences();
+		int changes = old.compare(gp);
+		if (changes != 0){
+			_globalPreferences.set(gp);
+		}
+		return changes;
+	}
+		
+	/**
+	 * Answer the project preferences for this project.
+	 * @param project The project, this may be null.
+	 */
 	public ProjectPreferences getProjectPreferences(IProject project) {
-		ProjectPreferences pp = getProjectPreferences2(project);
+		ProjectPreferences pp = _projectPreferences.get(project);
 		if (pp != null)return pp;
 		
 		/* hopefully we rarely get this far */
@@ -464,34 +596,22 @@
 		return pp;
 	}
 
-	
+	/**
+	 * 
+	 * @param project The project, this may be null.
+	 * @param baseValidators
+	 */
 	private ProjectPreferences getProjectPreferences(IProject project, Map<String, Validator> baseValidators) 
 		throws BackingStoreException {
-		if (_projectPreferences.containsKey(project)){
-			return _projectPreferences.get(project);
-		}
+		ProjectPreferences pp = _projectPreferences.get(project);
+		if (pp != null)return pp;
 		
 		ValPrefManagerProject vpm = new ValPrefManagerProject(project);
-		ProjectPreferences pp = new ProjectPreferences(project); 
-		vpm.loadProjectPreferences(pp, baseValidators);
+		pp = vpm.loadProjectPreferences(project, baseValidators);
 		_projectPreferences.put(project, pp);
 		return pp;		
 	}
-	
-	/**
-	 * Answer the project specific validation preferences from the cache
-	 * 
-	 * @param project
-	 * 
-	 * @return null if the project is not in the cache.
-	 */
-	private ProjectPreferences getProjectPreferences2(IProject project){
-		if (_projectPreferences.containsKey(project)){
-			return _projectPreferences.get(project);
-		}
-		return null;
-	}
-	
+		
 	/**
 	 * Restore all the validation defaults, as defined by the individual validators via the
 	 * validation extension point.
@@ -539,7 +659,7 @@
 				SubMonitor subMonitor = SubMonitor.convert(monitor);
 				String task = NLS.bind(ValMessages.LogValStart, validator.getName(), resource.getName());
 				subMonitor.beginTask(task, 1);
-				validate(validator, operation, resource, kind, subMonitor.newChild(1));
+				validate(validator, operation, resource, kind, subMonitor.newChild(1), null);
 			}			
 		};
 		SubMonitor sm = SubMonitor.convert(monitor, getValidators(project).length);
@@ -560,7 +680,7 @@
 	 * @param monitor
 	 */
 	public void validate(Validator validator, ValOperation operation, IResource resource, int kind, 
-			IProgressMonitor monitor){
+			IProgressMonitor monitor, ValidationEvent event){
 		if (operation.isValidated(validator.getId(), resource))return;
 		long time = 0;
 		long cpuTime = -1;
@@ -575,7 +695,7 @@
 		if (Tracing.matchesExtraDetail(validator.getId())){
 			Tracing.log("ValManager-03: validating ", resource); //$NON-NLS-1$
 		}
-		ValidationResult vr = validator.validate(resource, kind, operation, monitor);
+		ValidationResult vr = validator.validate(resource, kind, operation, monitor, event);
 		if (pm.isCollecting()){
 			if (cpuTime != -1){
 				cpuTime = Misc.getCPUTime() - cpuTime;
@@ -595,7 +715,7 @@
 			Tracing.log("ValManager-01: " + msg); //$NON-NLS-1$
 		}
 		if (vr != null){
-			operation.getResult().mergeResults(vr);
+			operation.mergeResults(vr);
 			if (vr.getSuspendValidation() != null)operation.suspendValidation(vr.getSuspendValidation(), validator);
 		}
 	}
@@ -616,7 +736,7 @@
 		
 		for (Validator val : getValidators(project)){
 			if (monitor.isCanceled())return;
-			if (!_projectManager.shouldValidate(val, project, valType))continue;
+			if (!ValidatorProjectManager.get().shouldValidate(val, project, valType))continue;
 			if (operation.isSuspended(val, project))continue;
 			try {
 				visitor.visit(val, project, valType, operation, monitor);
@@ -640,7 +760,7 @@
 		
 		Map<String,IValidatorGroupListener[]> groupListeners = new HashMap<String,IValidatorGroupListener[]>();
 		
-		ValProperty vp = getValProperty(resource, valType, _configNumber);
+		ValProperty vp = getValProperty(resource, valType, _configNumber.get());
 		if (vp != null){
 			BitSet bs = vp.getConfigSet();
 			for (Validator val : getValidators(project)){
@@ -664,11 +784,11 @@
 		}
 		
 		vp = new ValProperty();
-		vp.setConfigNumber(_configNumber);
+		vp.setConfigNumber(_configNumber.get());
 		ContentTypeWrapper ctw = new ContentTypeWrapper();
 		for (Validator val : getValidators(project)){
 			if (!monitor.isCanceled()) {
-				if (!_projectManager.shouldValidate(val, project, valType))continue;
+				if (!ValidatorProjectManager.get().shouldValidate(val, project, valType))continue;
 				if (Friend.shouldValidate(val, resource, valType, ctw)){
 					vp.getConfigSet().set(_idManager.getIndex(val.getId()));
 					// we do the suspend check after figuring out if it needs to be validated, because we save
@@ -766,7 +886,7 @@
 			// don't care about this one
 		}
 		if (vp == null)return null;
-		if (vp.getConfigNumber() != _configNumber)return null;
+		if (vp.getConfigNumber() != _configNumber.get())return null;
 		return vp;
 	}
 	
@@ -776,7 +896,9 @@
 	 * @param project The project that has been opened, created, or had it's description change.
 	 */
 	public void projectChanged(IProject project){
-		_projectManager.change(project);		
+		ValidatorProjectManager.reset();
+		_projectPreferences.remove(project);
+		_cache.reset(project);
 	}
 	
 	/**
@@ -786,7 +908,9 @@
 	 * 
 	 */
 	public void projectRemoved(IProject project){
-		_projectManager.remove(project);
+		ValidatorProjectManager.reset();
+		_projectPreferences.remove(project);
+		_cache.reset(project);
 	}
 	
 	private void putValProperty(ValProperty vp, IResource resource, ValType valType) {
@@ -810,7 +934,7 @@
 
 			public void visit(Validator validator, IProject project, ValType valType,
 				ValOperation operation, IProgressMonitor monitor) {
-				validator.clean(project, monitor);					
+				validator.clean(project, operation, monitor);					
 			}
 			
 		};
@@ -828,7 +952,7 @@
 
 			public void visit(Validator validator, IProject project, ValType valType,
 				ValOperation operation, IProgressMonitor monitor) {
-				validator.clean(project, monitor);					
+				validator.clean(project, operation, monitor);					
 			}
 			
 		};
@@ -844,11 +968,11 @@
 		}
 	}
 	
-	private class HasValidatorVisitor implements IResourceVisitor {
+	private final class HasValidatorVisitor implements IResourceVisitor {
 		
-		private boolean 	_hasValidator;
-		private boolean		_isManual;
-		private boolean		_isBuild;
+		private boolean 			_hasValidator;
+		private final boolean		_isManual;
+		private final boolean		_isBuild;
 		
 		public HasValidatorVisitor(boolean isManual, boolean isBuild){
 			_isManual = isManual;
@@ -881,13 +1005,13 @@
 	 * @author karasiuk
 	 *
 	 */
-	private static class ValidatorIdManager {
+	private final static class ValidatorIdManager {
 		
 		/**
 		 * Map validator id's to Integers. The integers correspond to bits in the ValProperty instances.
 		 */
-		private HashMap<String, Integer> _map = new HashMap<String, Integer>(100);
-		private HashMap<Integer, String> _reverseMap = new HashMap<Integer, String>(100);
+		private final Map<String, Integer> _map = new HashMap<String, Integer>(100);
+		private final Map<Integer, String> _reverseMap = new HashMap<Integer, String>(100);
 		
 		/** Next available bit. */
 		private int _next;
@@ -897,7 +1021,7 @@
 		 * @param id validator id.
 		 * @return index into the validator bit mask.
 		 */
-		public int getIndex(String id){
+		public synchronized int getIndex(String id){
 			Integer i = _map.get(id);
 			if (i != null)return i;
 			
@@ -913,11 +1037,11 @@
 		 * @param index
 		 * @return null if the index number has not been set.
 		 */
-		public String getId(Integer index){
+		public synchronized String getId(Integer index){
 			return _reverseMap.get(index);
 		}
 		
-		public void reset(){
+		public synchronized void reset(){
 			_map.clear();
 			_reverseMap.clear();
 			_next = 0;
@@ -927,7 +1051,7 @@
 		 * Answer the ids for the bit in the bitset. This is used for debugging. 
 		 * @param bs
 		 */
-		public String[] getIds(BitSet bs){
+		public synchronized String[] getIds(BitSet bs){
 			List<String> list = new LinkedList<String>();
 			for(int i=bs.nextSetBit(0); i>=0; i=bs.nextSetBit(i+1)) {
 				String id = getId(i);
@@ -941,14 +1065,59 @@
 	/**
 	 * This is used to keep track of which validators are enabled with which projects. We want to ensure
 	 * that we don't activate a validator (and it's plug-in) if it has nothing to validate in the workspace.
-	 * The ValManager keeps a single instance of this class. 
+	 * This is an immutable object.
 	 * @author karasiuk
 	 *
 	 */
-	private static class ValidatorProjectManager {
+	private final static class ValidatorProjectManager {
 		
-		private ValProjectMap _manual = new ValProjectMap(ValType.Manual);
-		private ValProjectMap _build = new ValProjectMap(ValType.Build);
+		private final static AtomicReference<ValidatorProjectManager> _me = new AtomicReference<ValidatorProjectManager>();
+		private final static AtomicInteger _counter = new AtomicInteger();
+		
+		private final ValProjectMap _manual = new ValProjectMap(ValType.Manual);
+		private final ValProjectMap _build = new ValProjectMap(ValType.Build);
+		private final int _sequence;
+		
+		/**
+		 * Answer the most current ValidatorProjectManager creating a new one if you have to.
+		 * @return
+		 */
+		public static ValidatorProjectManager get(){
+			ValidatorProjectManager vpm = _me.get();
+			if (vpm != null)return vpm;
+			
+			int next = _counter.incrementAndGet();
+			ValidatorProjectManager newVpm = null;
+			boolean looking = true;
+			while(looking){
+				vpm = _me.get();
+				if (vpm == null || next > vpm.getSequence()){
+					if (newVpm == null)newVpm = new ValidatorProjectManager(next);
+					if (_me.compareAndSet(vpm, newVpm))return newVpm;
+				}
+				else looking = false;
+			}
+			return vpm;
+		}
+		
+		/**
+		 * Reset the ValidatorProjectManager to null, which will force a newer one to be created the next time
+		 * that it is requested.
+		 */
+		public static void reset(){
+			int next = _counter.incrementAndGet();
+			ValidatorProjectManager vpm = _me.get();
+			if ( vpm == null)return;
+			if (next > vpm.getSequence())_me.compareAndSet(vpm, null);
+		}
+		
+		private ValidatorProjectManager(int sequence){
+			_sequence = sequence;
+		}
+		
+		int getSequence(){
+			return _sequence;
+		}
 		
 		/**
 		 * Should this validator attempt to validate any resources in this project?
@@ -962,55 +1131,41 @@
 		 *            The type of validation operation.
 		 * @return true if the validator should attempt to validate.
 		 */
-		public synchronized boolean shouldValidate(Validator validator, IProject project, ValType type){
+		public boolean shouldValidate(Validator validator, IProject project, ValType type){
 			if (type == ValType.Build)return _build.shouldValidate(validator, project);
 			if (type == ValType.Manual)return _manual.shouldValidate(validator, project);
 				
 			return false;
-		}
-		
-		/**
-		 * A project has been created, opened, or had it's description changed.
-		 * @param project
-		 */
-		public void change(IProject project) {
-			reset();
-		}
-		
-		public void remove(IProject project) {
-			reset();
-		}
-		
-		
-		public synchronized void reset(){
-			_build.reset();
-			_manual.reset();
-		}
-		
+		}		
+				
 		/**
 		 * This is used to keep track of which validators are enabled for which projects. We want to ensure
 		 * that we don't activate a validator (and it's plug-in) if it has nothing to validate in the workspace.
+		 * <p>
+		 * There are two reasons why a validator may not be enabled. It's current project level filters may not match
+		 * the project. Or the entire validator may have been turned off for the project. 
+		 * </p>
 		 * @author karasiuk
 		 *
 		 */
-		private static class ValProjectMap {
+		private final static class ValProjectMap {
 			/**
-			 * Map a validator to the projects that it validates. 
+			 * Map a validator to the projects that it validates. This is an immutable object.
 			 * <p>
 			 * I've gone back and forth on whether the key should
 			 * be a Validator or the validator id. I'm back to it being the id because I was
-			 * running into cases where because of copying I wasn't getting the matches that I expected. If I run into
+			 * running into cases where because of copying I wasn't getting the matches that I expected and I
+			 * want to ensure that I don't leak validators. If I run into
 			 * false matches, it is probably because reset isn't being called when it should be.
+			 * </p>
 			 */
-			private Map<String, Set<IProject>> _map = new HashMap<String, Set<IProject>>(50);
+			private final Map<String, Set<IProject>> _map;
 			
-			private ValType _type;
-			
-			/** Have we been initialized yet? */
-			private boolean	_initialized;
-			
+			private final ValType _type;
+						
 			public ValProjectMap(ValType type){
 				_type = type;
+				_map = load();
 			}
 			
 			/**
@@ -1025,8 +1180,7 @@
 			 *            
 			 * @return true if the validator should attempt to validate.
 			 */
-			public synchronized boolean shouldValidate(Validator validator, IProject project){
-				if (!_initialized)load();
+			public boolean shouldValidate(Validator validator, IProject project){
 				String vid = validator.getId();
 				Set<IProject> projects = _map.get(vid);
 				if (projects == null)return false;
@@ -1034,7 +1188,11 @@
 				return projects.contains(project);
 			}
 			
-			private void load() {
+			/**
+			 * For each of the projects in the workspace, load which validators are currently prepared to validate things.
+			 */
+			private Map<String, Set<IProject>> load() {
+				Map<String, Set<IProject>> map = new HashMap<String, Set<IProject>>(50);
 				ValManager vm = ValManager.getDefault();
 				IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
 				Tracing.log("ValManager-02: loading " + projects.length + " projects");  //$NON-NLS-1$//$NON-NLS-2$
@@ -1043,22 +1201,18 @@
 					Validator[] vals = vm.getValidators(project);
 					for (Validator v : vals){
 						String vid = v.getId();
-						Set<IProject> set = _map.get(vid);
+						Set<IProject> set = map.get(vid);
 						if (set == null){
 							set = new HashSet<IProject>(50);
-							_map.put(vid, set);
+							map.put(vid, set);
 						}
 						
 						if (v.shouldValidateProject(project, _type))set.add(project);
 					}					
 				}
-				_initialized = true;
+				return map;
 			}
 			
-			public synchronized void reset(){
-				_initialized = false;
-				_map.clear();
-			}
 		}
 		
 	}
@@ -1078,7 +1232,54 @@
 		case IProjectChangeListener.ProjectAdded:
 			projectChanged(project);
 			break;
+		}		
+	}
+	
+	/**
+	 * Store the singleton for the ValManager. This approach is used to avoid having to synchronize the
+	 * ValManager.getDefault() method.
+	 * 
+	 * @author karasiuk
+	 *
+	 */
+	private static class Singleton {
+		static ValManager valManager = new ValManager();
+	}
+	
+	private final class ValidatorCache {
+		private final ConcurrentMap<IProject, Validator[]> _cache = new ConcurrentHashMap<IProject, Validator[]>(50);
+		private final AtomicReference<Validator[]> _global = new AtomicReference<Validator[]>();
+		
+		public Validator[] getValidatorsCached(IProject project) throws ProjectUnavailableError {
+			Validator[] vals = null;
+			if (project == null){
+				vals = _global.get();
+				if (vals == null){				
+					vals = getValidatorsNotCached(project);
+					_global.set(vals);
+				}
+			}
+			else {
+				vals = _cache.get(project);
+				if (vals == null){
+					vals = getValidatorsNotCached(project);
+					_cache.put(project, vals);
+				}
+			}
+			return vals;
 		}
 		
+		public void reset(){
+			_cache.clear();
+			_global.set(null);
+		}
+		
+		public void reset(IProject project){
+			if (project != null)_cache.remove(project);
+		}
+
 	}
+	
+	public enum UseProjectPreferences {Normal, MustUse, MustNotUse}
+
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperation.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperation.java
index e5d8696..44c78ec 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperation.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperation.java
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -36,45 +35,65 @@
  * @author karasiuk
  *
  */
-public class ValOperation {
+public final class ValOperation {
 	
-	private ValidationState 	_state = new ValidationState();
-	private ValidationResult	_result = new ValidationResult();
-	private Map<IProject, Set<Validator>> _suspended = 
-		Collections.synchronizedMap(new HashMap<IProject, Set<Validator>>(40));
+	private final ValidationState 	_state = new ValidationState();
+	private final ValidationResult	_result = new ValidationResult();
+	
+	/**
+	 * Each project can have a set of validators that are suspended for the duration of the validation operation.
+	 * The set contains the validator's id.
+	 */
+	private final Map<IProject, Set<String>> _suspended = new HashMap<IProject, Set<String>>(40);
 	
 	/** The time that the operation started. */
-	private long	_started = System.currentTimeMillis();
+	private final long	_started = System.currentTimeMillis();
 	
 	/** 
-	 * Are we in a multi project validation? This can be triggered by either clean all or 
+	 * Are we in a multi project validation? That is, could we be validating several
+	 * projects at the same time? This can be triggered by either clean all or 
 	 * if auto build is turned off, a build all. 
 	 */
-	private boolean	_multiProject;
+	private final boolean	_multiProject;
 	
 	/** 
 	 * Holds all the resources that have been validated as a side-effect of running other validations.
 	 * The key is the validator id and the value is a Set of IResources.
 	 */
-	private Map<String, Set<IResource>> 	_validated = new HashMap<String, Set<IResource>>(20);
+	private final Map<String, Set<IResource>> 	_validated = new HashMap<String, Set<IResource>>(20);
 	
 	public ValOperation(){
+		_multiProject = false;
+	}
+	
+	/**
+	 * 
+	 * @param multiProject Set to true if we could be validating several projects at the same time.
+	 */
+	public ValOperation(boolean multiProject){
+		_multiProject = multiProject;
 	}
 	
 	public ValidationState getState() {
 		return _state;
 	}
-	public void setState(ValidationState state) {
-		_state = state;
-	}
-	public ValidationResult getResult() {
-		return _result;
-	}
 	
-	public void setResult(ValidationResult result) {
-		_result = result;
+	/**
+	 * Answer a summary of the validation results.
+	 * @return
+	 */
+	public ValidationResultSummary getResult() {
+		synchronized(_result){
+			ValidationResultSummary vrs = new ValidationResultSummary(_result.getSeverityError(), 
+				_result.getSeverityWarning(), _result.getSeverityInfo());
+			return vrs;
+		}
 	}
-	
+		
+	/**
+	 * Answer a copy of the ValidationResult.
+	 * @return
+	 */
 	public ValidationResults getResults(){
 		return new ValidationResults(_result);
 	}
@@ -86,12 +105,14 @@
 	 * @param resource resource that has been validated.
 	 */
 	public void addValidated(String id, IResource resource){
-		Set<IResource> set = _validated.get(id);
-		if (set == null){
-			set = new HashSet<IResource>(20);
-			_validated.put(id, set);
+		synchronized(_validated){
+			Set<IResource> set = _validated.get(id);
+			if (set == null){
+				set = new HashSet<IResource>(20);
+				_validated.put(id, set);
+			}
+			set.add(resource);
 		}
-		set.add(resource);
 	}
 	
 	/**
@@ -102,30 +123,36 @@
 	 * @param resource
 	 */
 	public boolean isValidated(String id, IResource resource){
-		Set<IResource> set = _validated.get(id);
-		if (set == null)return false;
-		
-		return set.contains(resource);
+		synchronized(_validated){
+			Set<IResource> set = _validated.get(id);
+			if (set == null)return false;
+			
+			return set.contains(resource);
+		}
 	}
 
 	/**
-	 * Has this validator been suspended for the duration of this operation?
-	 *   
-	 * @param val
-	 * @param project can be null, in which case we return false
+	 * Has this validator been suspended for the duration of this operation on this project?
 	 * 
-	 * @return true if we already know that this validator should not run on this project.
+	 * @param val
+	 *            The validator that is being checked.
+	 * @param project
+	 *            Can be null, in which case we return false.
+	 * 
+	 * @return true if this validator should not run on this project.
 	 */
 	public boolean isSuspended(Validator val, IProject project) {
 		if (project == null)return false;
-		Set<Validator> set = getSuspended(project);		
-		return set.contains(val);
+		synchronized(_suspended){
+			Set<String> set = getSuspended(project);		
+			return set.contains(val.getId());
+		}
 	}
 	
-	private Set<Validator> getSuspended(IProject project){
-		Set<Validator> set = _suspended.get(project);
+	private Set<String> getSuspended(IProject project){
+		Set<String> set = _suspended.get(project);
 		if (set == null){
-			set = new HashSet<Validator>(5);
+			set = new HashSet<String>(5);
 			_suspended.put(project, set);
 		}
 		return set;
@@ -133,7 +160,8 @@
 
 	void suspendValidation(IProject project, Validator validator) {
 		if (project == null)return;
-		getSuspended(project).add(validator);
+		if (validator == null)return;
+		getSuspended(project).add(validator.getId());
 	}
 
 	public long getStarted() {
@@ -144,12 +172,34 @@
 		return _multiProject;
 	}
 
-	/** 
-	 * Are we in a multi project validation? That is, could we be validating several
-	 * projects at the same time? This can be triggered by either clean all or 
-	 * if auto build is turned off, a build all. 
+	/**
+	 * Indicate if the operation was canceled.
+	 * 
+	 * @param canceled
+	 * 		Set to true if it was canceled and false if it was not canceled.
 	 */
-	public void setMultiProject(boolean multiProject) {
-		_multiProject = multiProject;
-	}	
+	public void setCanceled(boolean canceled) {
+		synchronized (_result) {
+			_result.setCanceled(canceled);
+		}
+		
+	}
+
+	/**
+	 * Was the operation canceled before it completed? For example if the validation is being run through the
+	 * user interface, the end user can cancel the operation through the progress monitor.
+	 * 
+	 * @return true if the operation was canceled
+	 */
+	public boolean isCanceled() {
+		synchronized (_result) {
+			return _result.isCanceled();
+		}
+	}
+
+	public void mergeResults(ValidationResult vr) {
+		synchronized (_result) {
+			_result.mergeResults(vr);
+		}
+	}
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperationJob.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperationJob.java
deleted file mode 100644
index 9414c02..0000000
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperationJob.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.wst.validation.internal;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.wst.validation.ValidationFramework;
-import org.eclipse.wst.validation.Validator;
-import org.eclipse.wst.validation.internal.model.IValidatorVisitor;
-
-/**
- * This is used to signal when the entire validation operation is complete. This needs to be done in a job
- * because the operation isn't done, until all the validation jobs have finished.  
- * @author karasiuk
- *
- */
-public class ValOperationJob extends Job {
-	
-	private ValOperation _operation;
-	
-	public ValOperationJob(ValOperation operation){
-		super(ValMessages.JobNameMonitor);
-		_operation = operation;
-	}
-
-	@Override
-	protected IStatus run(IProgressMonitor monitor) {
-		boolean ok = true;
-		try {
-			ValidationFramework.getDefault().join(monitor);
-		}
-		catch (InterruptedException e){
-			ok = false;
-		}
-		finished(monitor);
-		return ok ? Status.OK_STATUS : Status.CANCEL_STATUS;
-	}
-	
-	private void finished(IProgressMonitor monitor){
-		IValidatorVisitor visitor = new IValidatorVisitor(){
-
-			public void visit(Validator validator, IProject project, ValType valType, 
-				ValOperation operation, IProgressMonitor monitor) {
-				
-				validator.validationFinishing(project, operation.getState(), monitor);					
-			}
-			
-		};
-		ValManager.getDefault().accept(visitor, null, ValType.Build, _operation, monitor);
-	}
-
-}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperationManager.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperationManager.java
deleted file mode 100644
index 1877a33..0000000
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValOperationManager.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.wst.validation.internal;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IResourceChangeEvent;
-import org.eclipse.core.resources.IResourceChangeListener;
-import org.eclipse.core.resources.IResourceDelta;
-import org.eclipse.core.resources.IWorkspace;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.wst.validation.Validator;
-import org.eclipse.wst.validation.internal.model.IValidatorVisitor;
-
-/**
- * Keep track of a validation operation when it is triggered as part of a build.
- * @author karasiuk
- *
- */
-public class ValOperationManager implements IResourceChangeListener {
-	
-	/*
-	 * I tried various tests to see what sort of change events I would get. This is what I 
-	 * observed using Eclipse 3.4:
-	 * 
-	 * Auto Build On
-	 * 
-	 *   Clean All
-	 *     - workspace, clean, pre
-	 *     - workspace, clean post
-	 *     - workspace, auto, post
-	 *     
-	 *   Clean Some
-	 *     - project1, clean, pre
-	 *     - project1, clean, post
-	 *     - project2, clean, pre
-	 *     - project2, clean, post
-	 *     - workspace, Auto, post
-	 *     
-	 *   Build Working Set - NA
-	 *   Build Project - NA
-	 *   Build All - NA
-	 *   
-	 *   Ctrl-S
-	 *     - workspace, auto, pre
-	 *     - workspace, auto, post
-	 *     
-	 * Auto build Off
-	 * 
-	 *   Clean All
-	 *     - same as (auto build on), but no workspace,auto,post event
-	 *     
-	 *   Clean Some 
-	 *     - same as (auto build on), but no workspace,auto,post event
-	 *     
-	 *   Build Working Set
-	 *     - project1, incremental, pre
-	 *     - project1, incremental, post
-	 *     - project2, incremental, pre
-	 *     - project2, incremental, post
-	 *     
-	 *   Build Project
-	 *     - same as above
-	 *     
-	 *   Build All
-	 *     - workspace, incremental, pre
-	 *     - workspace, incremental, post
-	 *     
-	 *   Ctrl-S - NA
-	 *   
-	 * For the case where a subset of the projects are built there is no way to guess whether they are part of the
-	 * same operation or not. Eclipse threats them as independent events, and so will the validation framework.
-	 * 
-	 * So for example, if the user selected two projects (p1 and p2) and built them, the framework would call the
-	 * validators like this:
-	 * 
-	 * validation starting on null
-	 * validation starting on P1
-	 *  - individual events per resource
-	 * validation finished on P1
-	 * validation finished on null 
-	 * 
-	 * validation starting on null
-	 * validation starting on P2
-	 *  - individual events per resource
-	 * validation finished on P2
-	 * validation finished on null 
-	 */
-	
-	private static ValOperationManager _me;
-
-	/**
-	 * This operation is in affect for a build cycle. At the end of the build it is reinitialized.
-	 */
-	private ValOperation 	_operation;
-	
-	
-	/**
-	 * In the very common case of doing a clean all (with auto build turned on), Eclipse signals two 
-	 * workspace, auto build, post events. One at the end of the clean and one at the end of the
-	 * real build.
-	 * 
-	 * If we are doing a clean all, with auto build turned on, we increment this by one, 
-	 * so that we know to throw away the first workspace, auto build, post event.
-	 */
-	private int _discardAutoPost;
-
-	public static synchronized ValOperationManager getDefault(){
-		if (_me == null)_me = new ValOperationManager();
-		return _me;
-	}
-	
-	private ValOperationManager(){}
-				
-	public void resourceChanged(IResourceChangeEvent event) {
-		int type = event.getType();
-		int kind = event.getBuildKind();
-		
-		if (kind == IncrementalProjectBuilder.CLEAN_BUILD && ((type & IResourceChangeEvent.PRE_BUILD) != 0)){
-			processClean(event);
-		}
-		
-		if (isBuildStarting(event)){
-			_operation = new ValOperation();
-			_operation.setMultiProject(true);
-			IValidatorVisitor visitor = new IValidatorVisitor(){
-
-				public void visit(Validator validator, IProject project, ValType valType, 
-					ValOperation operation, IProgressMonitor monitor) {
-					
-					validator.validationStarting(project, operation.getState(), monitor);					
-				}				
-			};
-			ValManager.getDefault().accept(visitor, null, ValType.Build, _operation, new NullProgressMonitor());
-			
-		}
-		
-		if (isBuildFinished(event)){
-			ValOperationJob finished = new ValOperationJob(getOperation());
-			finished.schedule();
-			_operation = null;
-		}
-		
-		
-		if (Tracing.isLogging()){
-			String kindName = null;
-			if (kind == IncrementalProjectBuilder.AUTO_BUILD)kindName = "Auto"; //$NON-NLS-1$
-			else if (kind == IncrementalProjectBuilder.CLEAN_BUILD)kindName = "Clean"; //$NON-NLS-1$
-			else if (kind == IncrementalProjectBuilder.FULL_BUILD)kindName = "Full"; //$NON-NLS-1$
-			else if (kind == IncrementalProjectBuilder.INCREMENTAL_BUILD)kindName = "Incremental"; //$NON-NLS-1$
-			else kindName = String.valueOf(kind);
-			
-			StringBuffer b = new StringBuffer(100);
-			
-			String sourceName = "unknown"; //$NON-NLS-1$
-			if (event.getSource() instanceof IResource) {
-				IResource res = (IResource) event.getSource();
-				sourceName = res.getName();
-			}
-			else if (event.getSource() instanceof IWorkspace) {
-				sourceName = "Workspace";			 //$NON-NLS-1$
-			}
-			b.append("ValOperationManager-01: A resource has changed, source="+sourceName+", kind="+kindName+", event type=("+type); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-			if ((type & IResourceChangeEvent.POST_BUILD) != 0)b.append(", post build"); //$NON-NLS-1$
-			if ((type & IResourceChangeEvent.PRE_BUILD) != 0){
-				b.append(", pre build"); //$NON-NLS-1$
-			}
-			b.append(')');
-			IResourceDelta rd = event.getDelta();
-			if (rd == null)b.append(", there was no resource delta"); //$NON-NLS-1$
-			
-			Tracing.log(b);
-		}
-		
-	}
-	
-	/**
-	 * Determine if we are starting a new build cycle.
-	 * @param event
-	 * @return
-	 */
-	private boolean isBuildStarting(IResourceChangeEvent event) {
-		int type = event.getType();
-		int kind = event.getBuildKind();
-		boolean isWorkspace = event.getSource() instanceof IWorkspace;
-		boolean preBuild = (type & IResourceChangeEvent.PRE_BUILD) != 0;
-		
-		if (ResourcesPlugin.getWorkspace().isAutoBuilding()){
-			if (isWorkspace && preBuild && kind == IncrementalProjectBuilder.CLEAN_BUILD){
-				_discardAutoPost = 1;
-				return true;
-			}
-			
-			if (isWorkspace && preBuild && kind == IncrementalProjectBuilder.AUTO_BUILD)return true;
-		}
-		else {
-			if (isWorkspace && preBuild && kind == IncrementalProjectBuilder.INCREMENTAL_BUILD)return true;
-		}
-		return false;
-	}
-
-	/**
-	 * Determine if we are at the end of a build cycle. This will give callers the ability to
-	 * clear caches etc.
-	 *  
-	 * @param event
-	 * @return return true if we are just finishing a build.
-	 */
-	private boolean isBuildFinished(IResourceChangeEvent event) {
-		
-		if (_operation == null)return false;
-		
-		int type = event.getType();
-		int kind = event.getBuildKind();
-		boolean isWorkspace = event.getSource() instanceof IWorkspace;
-		boolean postBuild = (type & IResourceChangeEvent.POST_BUILD) != 0;
-
-		
-		if (ResourcesPlugin.getWorkspace().isAutoBuilding()){
-			if (isWorkspace && postBuild && kind == IncrementalProjectBuilder.AUTO_BUILD){
-				if (_discardAutoPost == 1)_discardAutoPost = 0;
-				else return true;
-			}
-		}
-		else {
-			if (isWorkspace && postBuild && kind == IncrementalProjectBuilder.INCREMENTAL_BUILD)return true;
-		}
-		
-		return false;
-	}
-	
-	private void processClean(IResourceChangeEvent event){
-		// Originally I was using this to monitor IProject build requests as well, but that is not not needed
-		// since these will be handled by the IncrementalProjectBuilder.clean() method.
-		IProgressMonitor monitor = new NullProgressMonitor();
-		Object source = event.getSource();
-		if (source instanceof IWorkspace) {
-			ValManager.getDefault().clean(null, getOperation(), monitor);
-		}
-		
-	}
-
-	/**
-	 * Answer the current validation operation. If we are not in a multiple project validation
-	 * we will return a new one. 
-	 */
-	public ValOperation getOperation() {
-		/*
-		 * If we don't have a current operation, we create a new one. The only time we save
-		 * the operation is when we are sure that we are in a multi project validation.
-		 */
-		if (_operation == null)return new ValOperation();
-		return _operation;
-	}
-
-}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerGlobal.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerGlobal.java
index a187cfa..5fcbaf3 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerGlobal.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerGlobal.java
@@ -10,28 +10,31 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicReference;
 
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.wst.validation.Friend;
 import org.eclipse.wst.validation.MessageSeveritySetting;
-import org.eclipse.wst.validation.ValidationFramework;
 import org.eclipse.wst.validation.Validator;
 import org.eclipse.wst.validation.Validator.V2;
 import org.eclipse.wst.validation.internal.model.FilterGroup;
 import org.eclipse.wst.validation.internal.model.GlobalPreferences;
+import org.eclipse.wst.validation.internal.model.GlobalPreferencesValues;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 import org.osgi.service.prefs.BackingStoreException;
-import org.osgi.service.prefs.Preferences;
 
 /**
  * A class that knows how to manage the global persisted validation settings.
  * @author karasiuk
  */
-public class ValPrefManagerGlobal {
+public final class ValPrefManagerGlobal {
 	
 	/** 
 	 * Version of the framework properties.
@@ -43,20 +46,17 @@
 	 */
 	public final static int frameworkVersion = 3;
 	
-	private List<IValChangedListener> _listeners = new LinkedList<IValChangedListener>();
-	private static ValPrefManagerGlobal _me;
+	private final Set<IValChangedListener> _listeners = new CopyOnWriteArraySet<IValChangedListener>();
 	
-	private List<Validator> _validators;
+	private final AtomicReference<List<Validator>> _validators = new AtomicReference<List<Validator>>();
 	
 	private ValPrefManagerGlobal(){}
 	
 	public static ValPrefManagerGlobal getDefault(){
-		if (_me == null)_me = new ValPrefManagerGlobal();
-		return _me;
+		return Singleton.valPrefManagerGlobal;
 	}
 	
 	public void addListener(IValChangedListener listener){
-		if (_listeners.contains(listener))return;
 		_listeners.add(listener);
 	}
 	
@@ -106,10 +106,10 @@
 	 * Answer the v2 validators that have been overridden by the global preferences.
 	 */
 	public List<Validator> getValidators() throws BackingStoreException {
-		List<Validator> vals = _validators;
-		if (vals == null){
+		List<Validator> vals = _validators.get();
+		while (vals == null){
 			vals = loadValidators();
-			_validators = vals;
+			if (!_validators.compareAndSet(null, vals))vals = _validators.get();
 		}
 		return vals;
 	}
@@ -120,9 +120,9 @@
 	 */
 	private List<Validator> loadValidators() throws BackingStoreException {
 		LinkedList<Validator> list = new LinkedList<Validator>();
-		IEclipsePreferences pref = ValidationFramework.getDefault().getPreferenceStore();
+		PreferencesWrapper pref = PreferencesWrapper.getPreferences(null, null);
 		if (pref.nodeExists(PrefConstants.vals)){
-			Preferences vals = pref.node(PrefConstants.vals);
+			PreferencesWrapper vals = pref.node(PrefConstants.vals);
 			for (String id : vals.childrenNames()){
 				Validator base = ExtensionValidators.instance().getMapV2().get(id);
 				Validator v = loadValidator(id, vals, base);
@@ -150,10 +150,10 @@
 	 * @return A new validator that is a copy of the extension point validator
 	 *         with the updates from the preference store.
 	 */
-	static Validator loadValidator(String id, Preferences valsNode, Validator base) {
+	static Validator loadValidator(String id, PreferencesWrapper valsNode, Validator base) {
 		if (base == null)return null;
 		
-		Preferences vp = valsNode.node(id);
+		PreferencesWrapper vp = valsNode.node(id);
 		base = base.copy();
 		V2 v2 = base.asV2Validator();
 
@@ -182,16 +182,18 @@
 	 * 
 	 * @see ValManager#getGlobalPreferences()
 	 */
-	public void loadGlobalPreferences(GlobalPreferences gp) {
-		IEclipsePreferences pref = ValidationFramework.getDefault().getPreferenceStore();
-		gp.setSaveAutomatically(pref.getBoolean(PrefConstants.saveAuto, GlobalPreferences.DefaultAutoSave));
-		gp.setDisableAllValidation(pref.getBoolean(PrefConstants.suspend, GlobalPreferences.DefaultSuspend));
-		gp.setConfirmDialog(pref.getBoolean(PrefConstants.confirmDialog, GlobalPreferences.DefaultConfirm));
-		gp.setOverride(pref.getBoolean(PrefConstants.override, GlobalPreferences.DefaultOverride));
-		gp.setVersion(pref.getInt(PrefConstants.frameworkVersion, GlobalPreferences.DefaultFrameworkVersion));
-		gp.setStateTimeStamp(pref.getLong(PrefConstants.stateTS, 0));
+	public GlobalPreferences loadGlobalPreferences() {
+		PreferencesWrapper pref = PreferencesWrapper.getPreferences(null, null);
+		GlobalPreferencesValues gp = new GlobalPreferencesValues();
+		gp.saveAutomatically = pref.getBoolean(PrefConstants.saveAuto, GlobalPreferences.DefaultAutoSave);
+		gp.disableAllValidation = pref.getBoolean(PrefConstants.suspend, GlobalPreferences.DefaultSuspend);
+		gp.confirmDialog = pref.getBoolean(PrefConstants.confirmDialog, GlobalPreferences.DefaultConfirm);
+		gp.override = pref.getBoolean(PrefConstants.override, GlobalPreferences.DefaultOverride);
+		gp.version = pref.getInt(PrefConstants.frameworkVersion, GlobalPreferences.DefaultFrameworkVersion);
+		gp.stateTimeStamp = pref.getLong(PrefConstants.stateTS, 0);
 		
-		if (gp.getVersion() != frameworkVersion)migrate(gp.getVersion(), pref);
+		if (gp.version != frameworkVersion)migrate(gp.version, pref);
+		return new GlobalPreferences(gp);
 	}
 	
 	/**
@@ -199,7 +201,7 @@
 	 * @param version The incoming version of the preferences.
 	 * @param pref the root of the preference store
 	 */
-	static void migrate(int version, IEclipsePreferences pref) {
+	static void migrate(int version, PreferencesWrapper pref) {
 		try {
 			boolean update = false;
 			if (version == 2){
@@ -282,20 +284,27 @@
 	 *            validators. If we are updating a project's validators, then
 	 *            this map would be the preference page validators.
 	 */
-	static void save(Validator validator, Preferences root, Map<String, Validator> baseValidators) throws BackingStoreException {
+	static void save(Validator validator, PreferencesWrapper root, Map<String, Validator> baseValidators) throws BackingStoreException {
 		Validator.V2 v2 = validator.asV2Validator();
 		if (v2 == null)return;
 		
-		Preferences vp = root.node(validator.getId());
-		if (validator.sameConfig(baseValidators.get(validator.getId()))){
-			vp.removeNode();
+		final String id = validator.getId();
+		boolean hasNode = root.nodeExists(id);
+		
+		if (validator.sameConfig(baseValidators.get(id))){
+			if (hasNode){
+				PreferencesWrapper vp = root.node(id);
+				vp.removeNode();
+			}
 			return;
 		}
 		if (!validator.isChanged())return;
-		if (validator.getChangeCountGlobal() > 0){
+		PreferencesWrapper vp = root.node(id);
+		if (validator.hasGlobalChanges()){
 			Global g = new Global(validator.isManualValidation(), validator.isBuildValidation(), validator.getVersion(),
 				validator.getDelegatingId());
 			vp.put(PrefConstants.global, g.serialize());
+			Friend.setMigrated(validator, false);
 		}
 		
 		if (validator.getChangeCountMessages() > 0){
@@ -314,15 +323,58 @@
 			}
 		}
 	}
+	/**
+	 * Save the validator into the preference store.
+	 * 
+	 * @param validator
+	 *            The validator being saved.
+	 * 
+	 * @param root
+	 *            The top of the preference tree for validators, i.e.
+	 *            /instance/validator-framework-id/vals for workspace validators
+	 *            and /vals for project validators.
+	 *            
+	 * @param baseValidators
+	 *            A map of the validators that are one level higher in the
+	 *            storage hierarchy. So if we are updating the preference page
+	 *            validators, then this map would be the extension point
+	 *            validators. If we are updating a project's validators, then
+	 *            this map would be the preference page validators.
+	 */
+	static void save(ValidatorMutable validator, PreferencesWrapper root, Map<String, Validator> baseValidators) throws BackingStoreException {
+		if (!validator.isV2Validator())return;
+		
+		PreferencesWrapper vp = root.node(validator.getId());
+		if (validator.sameConfig(baseValidators.get(validator.getId()))){
+			vp.removeNode();
+			return;
+		}
+		if (!validator.isChanged())return;
+		if (validator.hasGlobalChanges()){
+			Global g = new Global(validator.isManualValidation(), validator.isBuildValidation(), validator.getVersion(),
+				validator.getDelegatingId());
+			vp.put(PrefConstants.global, g.serialize());
+//			Friend.setMigrated(validator, false);
+		}
+				
+		if (validator.getChangeCountGroups() > 0){
+			FilterGroup[] groups = validator.getGroups();
+			if (groups.length > 0){
+				Serializer ser = new Serializer(500);
+				for (FilterGroup group : groups)group.save(ser);
+				vp.put(PrefConstants.groups, ser.toString());
+			}
+		}
+	}
 	
 	public void saveAsPrefs(Validator[] val) {
 		try {
-			IEclipsePreferences pref = ValidationFramework.getDefault().getPreferenceStore();
-			Preferences vals = pref.node(PrefConstants.vals);
+			PreferencesWrapper pref = PreferencesWrapper.getPreferences(null, null);
+			PreferencesWrapper vals = pref.node(PrefConstants.vals);
 			Map<String, Validator> base = ExtensionValidators.instance().getMapV2();
 			for (Validator v : val)save(v, vals, base);
 			pref.flush();
-			_validators = null;
+			_validators.set(null);
 			updateListeners(true);
 		}
 		catch (BackingStoreException e){
@@ -336,14 +388,14 @@
 	 */
 	public synchronized void savePreferences(GlobalPreferences gp, Validator[] validators){
 		try {
-			IEclipsePreferences prefs = ValidationFramework.getDefault().getPreferenceStore();
+			PreferencesWrapper prefs = PreferencesWrapper.getPreferences(null, null);
 			savePreferences(prefs, gp);
-			Preferences vals = prefs.node(PrefConstants.vals);
+			PreferencesWrapper vals = prefs.node(PrefConstants.vals);
 
 			Map<String, Validator> base = ExtensionValidators.instance().getMapV2();
 			for (Validator v : validators)save(v, vals, base);
 			prefs.flush();
-			_validators = null;
+			_validators.set(null);
 			updateListeners(true);
 		}
 		catch (BackingStoreException e){
@@ -354,13 +406,79 @@
 	/**
 	 * Save the global preferences and the validators.
 	 */
-	public synchronized void savePreferences(GlobalPreferences gp){
+	public synchronized void savePreferences(GlobalPreferences gp, ValidatorMutable[] validators, Boolean persist){
 		try {
-			IEclipsePreferences prefs = ValidationFramework.getDefault().getPreferenceStore();
-			boolean isConfigChange = gp.isConfigChange();
+			PreferencesWrapper prefs = PreferencesWrapper.getPreferences(null, persist);
+			savePreferences(prefs, gp);
+			PreferencesWrapper vals = prefs.node(PrefConstants.vals);
+			Map<String, Validator> base = ExtensionValidators.instance().getMapV2();
+			for (ValidatorMutable v : validators)save(v, vals, base);
+
+			prefs.flush();
+			_validators.set(null);
+			updateListeners(true);
+		}
+		catch (BackingStoreException e){
+			ValidationPlugin.getPlugin().handleException(e);
+		}
+	}
+		
+	/**
+	 * Save the V1 preferences, so that the old validators continue to work.
+	 */
+	public static void saveV1Preferences(ValidatorMutable[] validators, Boolean persistent){
+		try {
+			GlobalConfiguration gc = ConfigurationManager.getManager().getGlobalConfiguration();
+			gc.setEnabledManualValidators(getEnabledManualValidators(validators));				
+			gc.setEnabledBuildValidators(getEnabledBuildValidators(validators));
+
+			gc.passivate();
+			gc.store(persistent);
+		}
+		catch (InvocationTargetException e){
+			ValidationPlugin.getPlugin().handleException(e);
+		}			
+	}
+
+	/**
+	 * Answer all the V1 validators that are manually enabled.
+	 * @return
+	 */
+	private static ValidatorMetaData[] getEnabledManualValidators(ValidatorMutable[] validators) {
+		List<ValidatorMetaData> list = new LinkedList<ValidatorMetaData>();
+		for (ValidatorMutable v : validators){
+			if (v.isManualValidation() && v.isV1Validator())list.add(v.getVmd());
+		}
+		ValidatorMetaData[] result = new ValidatorMetaData[list.size()];
+		list.toArray(result);
+		return result;
+	}
+
+	/**
+	 * Answer all the V1 validators that are enabled for build.
+	 * @return
+	 */
+	private static ValidatorMetaData[] getEnabledBuildValidators(ValidatorMutable[] validators) {
+		List<ValidatorMetaData> list = new LinkedList<ValidatorMetaData>();
+		for (ValidatorMutable v : validators){
+			if (v.isBuildValidation() && v.isV1Validator())list.add(v.getVmd());
+		}
+		ValidatorMetaData[] result = new ValidatorMetaData[list.size()];
+		list.toArray(result);
+		return result;
+	}
+
+	
+	/**
+	 * Save the global preferences and the validators.
+	 */
+	public synchronized void savePreferences(){
+		try {
+			GlobalPreferences gp = ValManager.getDefault().getGlobalPreferences();
+			PreferencesWrapper prefs = PreferencesWrapper.getPreferences(null, null);
 			savePreferences(prefs, gp);
 			prefs.flush();
-			updateListeners(isConfigChange);
+			updateListeners(true);
 		}
 		catch (BackingStoreException e){
 			ValidationPlugin.getPlugin().handleException(e);
@@ -370,7 +488,7 @@
 	/**
 	 * Save the global preferences and the validators.
 	 */
-	private void savePreferences(IEclipsePreferences prefs, GlobalPreferences gp){
+	private void savePreferences(PreferencesWrapper prefs, GlobalPreferences gp){
 		prefs.putBoolean(PrefConstants.saveAuto, gp.getSaveAutomatically());
 		prefs.putBoolean(PrefConstants.suspend, gp.getDisableAllValidation());
 		prefs.putLong(PrefConstants.stateTS, gp.getStateTimeStamp());
@@ -385,7 +503,7 @@
 	 * @param settings
 	 */
 	public void loadMessages(Validator validator, Map<String, MessageSeveritySetting> settings) {
-		IEclipsePreferences pref = ValidationFramework.getDefault().getPreferenceStore();
+		PreferencesWrapper pref = PreferencesWrapper.getPreferences(null, null);
 		try {
 			loadMessageSettings(validator, settings, pref);
 		}
@@ -401,14 +519,14 @@
 	 * @param settings
 	 * @param root the root of the preference store
 	 */
-	static void loadMessageSettings(Validator val, Map<String, MessageSeveritySetting> settings, Preferences root) 
+	static void loadMessageSettings(Validator val, Map<String, MessageSeveritySetting> settings, PreferencesWrapper root) 
 		throws BackingStoreException {
 		if (!root.nodeExists(PrefConstants.vals))return;
 		
-		Preferences vals = root.node(PrefConstants.vals); 
+		PreferencesWrapper vals = root.node(PrefConstants.vals); 
 		if (!vals.nodeExists(val.getId()))return;
 		
-		Preferences valPrefs = vals.node(val.getId());
+		PreferencesWrapper valPrefs = vals.node(val.getId());
 		String msgs = valPrefs.get(PrefConstants.msgs, ""); //$NON-NLS-1$
 		if (msgs.length() == 0)return;
 		
@@ -446,18 +564,18 @@
 //		}
 //	}
 	
-	private static class Global {
-		private boolean _manual;
-		private boolean _build;
-		private int		_version;
-		private String	_delegating;
+	private final static class Global {
+		private final boolean 	_manual;
+		private final boolean 	_build;
+		private final int		_version;
+		private final String	_delegating;
 		
 		public Global(String value){
 			Deserializer d = new Deserializer(value);
 			_manual = d.getBoolean();
 			_build = d.getBoolean();
 			_version = d.getInt();
-			if (d.hasNext())_delegating = d.getString();
+			_delegating = d.hasNext() ? d.getString() : null;
 		}
 		
 		public Global(boolean manual, boolean build, int version, String delegating){
@@ -493,7 +611,7 @@
 		}
 	}
 	
-	private static class Msgs {
+	private final static class Msgs {
 		public static String serialize(Collection<MessageSeveritySetting> messages){
 			Serializer s = new Serializer(100);
 			for (MessageSeveritySetting ms : messages){
@@ -520,4 +638,16 @@
 			return map;
 		}
 	}
+	
+	/**
+	 * Store the singleton for the ValPrefManagerGlobal. This approach is used to avoid having to synchronize the
+	 * ValPrefManagerGlobal.getDefault() method.
+	 * 
+	 * @author karasiuk
+	 *
+	 */
+	private final static class Singleton {
+		final static ValPrefManagerGlobal valPrefManagerGlobal = new ValPrefManagerGlobal();
+	}
+
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerProject.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerProject.java
index 706f595..c28b031 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerProject.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValPrefManagerProject.java
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -18,27 +19,31 @@
 import java.util.Set;
 
 import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.ProjectScope;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.wst.validation.Friend;
+import org.eclipse.wst.validation.IMutableValidator;
 import org.eclipse.wst.validation.MessageSeveritySetting;
+import org.eclipse.wst.validation.MutableProjectSettings;
 import org.eclipse.wst.validation.Validator;
 import org.eclipse.wst.validation.Validator.V2;
 import org.eclipse.wst.validation.internal.model.ProjectPreferences;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
 import org.osgi.service.prefs.BackingStoreException;
-import org.osgi.service.prefs.Preferences;
 
 /**
  * A class that knows how to manage the project level persisted validation settings.
  * @author karasiuk
  *
  */
-public class ValPrefManagerProject {
+public final class ValPrefManagerProject {
 	
-	private IProject	_project;
-	private static List<IValChangedListener> _listeners = new LinkedList<IValChangedListener>();
+	private final IProject	_project;
+	private final static List<IValChangedListener> _listeners = new LinkedList<IValChangedListener>();
 	
+	/**
+	 * The validators that are in the project preference file, but have
+	 * only been configured to the global preference level. That is they have not had
+	 * any project level customizations applied yet.
+	 */
 	private List<Validator> _validators;
 	
 	public ValPrefManagerProject(IProject project){
@@ -66,20 +71,24 @@
 	 * @return true if it has settings. This does not mean that the settings are enabled, only that it
 	 * has settings.
 	 * 
-	 * @see ValManager#hasEnabledProjectPreferences(IProject)
+	 * @deprecated
 	 */
 	public boolean hasProjectSpecificSettings(){
-		IEclipsePreferences pref = getPreferences();
+		PreferencesWrapper pref = getPreferences(null);
 		
 		if (pref == null)return false;
-		int version = pref.getInt(PrefConstants.frameworkVersion, 0);
-		if (version == 0)return false;
-
 		return true;
 	}
 	
 	/**
-	 * Answer the v2 validators that have been overridden by the global preferences.
+	 * Answer the v2 validators that have been overridden by the project
+	 * preferences. The validators will not have the preference store's
+	 * customizations applied yet. The purpose of this method, is to identify the subset of validators 
+	 * that may later be configured.
+	 * 
+	 * @param baseValidators
+	 *            V2 validators from the extension points, and customized by any
+	 *            global preferences.
 	 */
 	public List<Validator> getValidators(Map<String, Validator> baseValidators) throws BackingStoreException {
 		List<Validator> vals = _validators;
@@ -91,14 +100,22 @@
 	}
 	
 	/**
-	 * Load the validators from the preference store.
-	 * @return the validators that have been overridden by the global references.
+	 * Load the validators from the preference store. The validators will not have the preference store's
+	 * customizations applied yet. The purpose of this method, is to identify the subset of validators 
+	 * that may later be configured.
+	 * 
+	 * @param baseValidators
+	 *            V2 validators from the extension points, and customized by any
+	 *            global preferences.
+	 * @return the validators that are in the project preference file, but have
+	 *         only been configured to the global preference level. That is they have not had
+	 *         any project level customizations applied yet.
 	 */
 	private List<Validator> loadValidators(Map<String, Validator> baseValidators) throws BackingStoreException {
-		LinkedList<Validator> list = new LinkedList<Validator>();
-		IEclipsePreferences pref = getPreferences();
+		List<Validator> list = new LinkedList<Validator>();
+		PreferencesWrapper pref = getPreferences(null);
 		if (pref.nodeExists(PrefConstants.vals)){
-			Preferences vals = pref.node(PrefConstants.vals);
+			PreferencesWrapper vals = pref.node(PrefConstants.vals);
 			for (String id : vals.childrenNames()){
 				Validator base = baseValidators.get(id);
 				Validator v = ValPrefManagerGlobal.loadValidator(id, vals, base);
@@ -111,40 +128,93 @@
 		}
 		return list;
 	}
-	
+		
 	/**
-	 * Update the project preferences from the preference store.
-	 * @return false if the project does not have any specific preferences.
+	 * Answer the setting of the getOverride field.
 	 */
-	public boolean loadProjectPreferencesShallow(ProjectPreferences pp) {
-		IEclipsePreferences pref = getPreferences();
+	public boolean getOverride(){
+		PreferencesWrapper pref = getPreferences(null);
 		
-		if (pref == null)return false;
+		if (!pref.nodeExists())return ProjectPreferences.DefaultOverride;
+		
 		int version = pref.getInt(PrefConstants.frameworkVersion, 0);
-		if (version == 0)return false;
-		
-		if (version != ValPrefManagerGlobal.frameworkVersion)ValPrefManagerGlobal.migrate(version, pref);
+		if (version == 0){
+			try {
+				ProjectConfiguration pc = ConfigurationManager.getManager().getProjectConfiguration(_project);
+				return pc.getDoesProjectOverride();
+			}
+			catch (InvocationTargetException e){
+				// eat it, if it fails we just go with the defaults
+			}
+		}
+		return pref.getBoolean(PrefConstants.override, ProjectPreferences.DefaultOverride);
+	}
 
-		pp.setOverride(pref.getBoolean(PrefConstants.override, ProjectPreferences.DefaultOverride));
-		pp.setSuspend(pref.getBoolean(PrefConstants.suspend, ProjectPreferences.DefaultSuspend));
-		return true;
+	private ProjectPreferences migrateFromBeforeWTP30(IProject project, Map<String, Validator> baseValidators) {
+		try {
+			ProjectConfiguration pc = ConfigurationManager.getManager().getProjectConfiguration(project);
+			
+			List<Validator> list = migrateFromBeforeWTP30(baseValidators, pc);
+			Validator[] vals = new Validator[list.size()];
+			list.toArray(vals);
+			return new ProjectPreferences(project, pc.getDoesProjectOverride(), pc.isDisableAllValidation(), vals);
+		}
+		catch (InvocationTargetException e){
+			// eat it, if it fails we just go with the defaults
+		}
+		return new ProjectPreferences(project);
+	}
+
+	private List<Validator> migrateFromBeforeWTP30(Map<String, Validator> baseValidators, ProjectConfiguration pc)
+			throws InvocationTargetException {
+				
+		Set<String> build = pc.getEnabledBuildlValidators();
+		Set<String> manual = pc.getEnabledManualValidators();
+		
+		List<Validator> list = new LinkedList<Validator>();
+		for (Validator v : baseValidators.values()){
+			V2 v2 = v.asV2Validator();
+			if (v2 != null){
+				boolean isBuild = build == null || build.contains(v2.getValidatorClassname());
+				boolean isManual = manual == null || manual.contains(v2.getValidatorClassname());
+				if ((v.isBuildValidation() != isBuild) || (v.isManualValidation() != isManual)){
+					V2 copy = v2.copy().asV2Validator();
+					copy.setBuildValidation(isBuild);
+					copy.setManualValidation(isManual);
+					copy.setLevel(Validator.Level.Project);
+					Friend.setMigrated(copy, true);
+					list.add(copy);
+				}
+			}
+		}
+		return list;
 	}
 	
 	
-	//FIXME I suspect that this method should be removed	
 	/**
-	 * Update the project preferences from the preference store.
-	 * @return false if the project does not have any specific preferences.
+	 * Answer the project preferences from the preference store.
+	 * @return null if the project does not have any specific preferences.
 	 */
-	public boolean loadProjectPreferences(ProjectPreferences pp, Map<String, Validator> baseValidators) 
+	public ProjectPreferences loadProjectPreferences(IProject project, Map<String, Validator> baseValidators) 
 		throws BackingStoreException {
 		
-		if (!loadProjectPreferencesShallow(pp))return false;
+		PreferencesWrapper pref = getPreferences(null);
+
+		if (pref == null)return null;
+		int version = pref.getInt(PrefConstants.frameworkVersion, 0);
+		if (version == 0){
+			// This means that we have a project that is before WTP 3.0
+			return migrateFromBeforeWTP30(project, baseValidators);
+		}
 		
-		IEclipsePreferences pref = getPreferences();
-		if (!pref.nodeExists(PrefConstants.vals))return true;
+		if (version != ValPrefManagerGlobal.frameworkVersion)ValPrefManagerGlobal.migrate(version, pref);
+
+		if (!pref.nodeExists(PrefConstants.vals)){
+			return new ProjectPreferences(project, pref.getBoolean(PrefConstants.override, ProjectPreferences.DefaultOverride),
+				pref.getBoolean(PrefConstants.suspend, ProjectPreferences.DefaultSuspend), new Validator[0]);
+		}
 		
-		Preferences vp = pref.node(PrefConstants.vals);
+		PreferencesWrapper vp = pref.node(PrefConstants.vals);
 		List<Validator> list = new LinkedList<Validator>();
 		for (String id : vp.childrenNames()){
 			Validator base = baseValidators.get(id);
@@ -157,25 +227,25 @@
 		}
 		Validator[] vals = new Validator[list.size()];
 		list.toArray(vals);
-		pp.setValidators(vals);
-		return true;
+		return new ProjectPreferences(project, pref.getBoolean(PrefConstants.override, ProjectPreferences.DefaultOverride),
+			pref.getBoolean(PrefConstants.suspend, ProjectPreferences.DefaultSuspend), vals);
 	}
 
-	private IEclipsePreferences getPreferences() {
-		IScopeContext projectContext = new ProjectScope(_project);
-		IEclipsePreferences pref = projectContext.getNode(ValidationPlugin.PLUGIN_ID);
-		return pref;
+	private PreferencesWrapper getPreferences(Boolean persist) {
+		return PreferencesWrapper.getPreferences(_project, persist);
 	}
 
-	public void savePreferences(ProjectPreferences projectPreferences, Validator[] validators) {
-		IEclipsePreferences pref = getPreferences();
+	public void savePreferences(ProjectPreferences projectPreferences) {
+		Validator[] validators = projectPreferences.getValidators();
+		PreferencesWrapper pref = getPreferences(null);
 		pref.putBoolean(PrefConstants.suspend, projectPreferences.getSuspend());
 		pref.putBoolean(PrefConstants.override, projectPreferences.getOverride());
 		pref.putInt(PrefConstants.frameworkVersion, ValPrefManagerGlobal.frameworkVersion);
-		Preferences vals = pref.node(PrefConstants.vals);
+		PreferencesWrapper vals = pref.node(PrefConstants.vals);
 		try {
 			Validator[] workspaceVals = ValManager.getDefault().getValidators();
 			Map<String, Validator> base = new HashMap<String, Validator>(workspaceVals.length);
+			for (Validator v : workspaceVals)base.put(v.getId(), v);
 			for (Validator v : validators)ValPrefManagerGlobal.save(v, vals, base);
 			pref.flush();
 			ProjectConfiguration pc = ConfigurationManager.getManager()
@@ -190,6 +260,67 @@
 			ValidationPlugin.getPlugin().handleException(e);
 		}		
 	}
+
+	public void savePreferences(ProjectPreferences projectPreferences, ValidatorMutable[] validators) {
+		PreferencesWrapper pref = getPreferences(null);
+		pref.putBoolean(PrefConstants.suspend, projectPreferences.getSuspend());
+		pref.putBoolean(PrefConstants.override, projectPreferences.getOverride());
+		pref.putInt(PrefConstants.frameworkVersion, ValPrefManagerGlobal.frameworkVersion);
+		try {
+			savePreferences(validators, false, null);
+			pref.flush();
+			updateListeners(_project);
+		}
+		catch (Exception e){
+			ValidationPlugin.getPlugin().handleException(e);
+		}		
+	}
+	
+	public void savePreferences(MutableProjectSettings settings, Boolean persist){
+		IProject project = settings.getProject();
+		PreferencesWrapper pref = PreferencesWrapper.getPreferences(project, persist);
+		pref.putBoolean(PrefConstants.suspend, settings.getSuspend());
+		pref.putBoolean(PrefConstants.override, settings.getOverride());
+		pref.putInt(PrefConstants.frameworkVersion, ValPrefManagerGlobal.frameworkVersion);
+		
+		IMutableValidator[] vms = settings.getValidators();
+		ValidatorMutable[] validators = new ValidatorMutable[vms.length];
+		for (int i=0; i<vms.length;i++)validators[i] = (ValidatorMutable)vms[i];
+		
+		try {
+			savePreferences(validators, false, persist);
+			pref.flush();
+			updateListeners(project);
+		}
+		catch (Exception e){
+			if (project.isAccessible())ValidationPlugin.getPlugin().handleException(e);
+		}
+	}
+	
+	public void savePreferences(ValidatorMutable[] validators, boolean flush, Boolean persist){
+		PreferencesWrapper pref = getPreferences(persist);
+		pref.putInt(PrefConstants.frameworkVersion, ValPrefManagerGlobal.frameworkVersion);
+		PreferencesWrapper vals = pref.node(PrefConstants.vals);
+		try {
+			Validator[] workspaceVals = ValManager.getDefault().getValidators();
+			Map<String, Validator> base = new HashMap<String, Validator>(workspaceVals.length);
+			for (Validator v : workspaceVals)base.put(v.getId(), v);
+			for (ValidatorMutable v : validators)ValPrefManagerGlobal.save(v, vals, base);
+			ProjectConfiguration pc = ConfigurationManager.getManager().getProjectConfiguration(_project);
+			pc.setEnabledBuildValidators(getEnabledBuildValidators(validators));
+			pc.setEnabledManualValidators(getEnabledManualValidators(validators));
+			pc.passivate();
+			pc.store();
+			if (flush){
+				pref.flush();
+				updateListeners(_project);
+			}
+		}
+		catch (Exception e){
+			ValidationPlugin.getPlugin().handleException(e);
+		}		
+		
+	}
 	
 	/**
 	 * Answer all the V1 validators that are enabled for build.
@@ -207,6 +338,18 @@
 	}
 	
 	/**
+	 * Answer all the V1 validators that are enabled for build.
+	 * @return
+	 */
+	private Set<ValidatorMetaData> getEnabledBuildValidators(ValidatorMutable[] validators) {
+		Set<ValidatorMetaData> set = new HashSet<ValidatorMetaData>(50);
+		for (ValidatorMutable v : validators){
+			if (v.isBuildValidation() && v.isV1Validator())set.add(v.getVmd());
+		}
+		return set;
+	}
+	
+	/**
 	 * Answer all the V1 validators that are enabled for manual validation.
 	 * @return
 	 */
@@ -221,9 +364,21 @@
 		return set;
 	}
 	
+	/**
+	 * Answer all the V1 validators that are enabled for manual validation.
+	 * @return
+	 */
+	private Set<ValidatorMetaData> getEnabledManualValidators(ValidatorMutable[] validators) {
+		Set<ValidatorMetaData> set = new HashSet<ValidatorMetaData>(50);
+		for (ValidatorMutable v : validators){
+			if (v.isManualValidation() && v.isV1Validator())set.add(v.getVmd());
+		}
+		return set;
+	}
+	
 	public void loadMessages(Validator validator, Map<String, MessageSeveritySetting> settings) {
 		try {
-			ValPrefManagerGlobal.loadMessageSettings(validator, settings, getPreferences());
+			ValPrefManagerGlobal.loadMessageSettings(validator, settings, getPreferences(null));
 		}
 		catch (BackingStoreException e){
 			ValidationPlugin.getPlugin().handleException(e);
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidationResultSummary.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidationResultSummary.java
new file mode 100644
index 0000000..9e91217
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidationResultSummary.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 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.validation.internal;
+
+/**
+ * An immutable object that holds a summary of the validation.
+ * @author karasiuk
+ *
+ */
+public final class ValidationResultSummary {
+	
+	private final int 	_error;
+	private final int 	_warning;
+	private final int	_info;
+	
+	public ValidationResultSummary(int error, int warning, int info){
+		_error = error;
+		_warning = warning;
+		_info = info;
+	}
+
+	public int getSeverityError() {
+		return _error;
+	}
+
+	public int getSeverityWarning() {
+		return _warning;
+	}
+
+	public int getSeverityInfo() {
+		return _info;
+	}
+
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidationRunner.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidationRunner.java
index dd33d82..01bf297 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidationRunner.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidationRunner.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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,9 +10,12 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal;
 
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceDelta;
@@ -27,10 +30,15 @@
 
 /**
  * Run the validators on a selected set of resources.
+ * <p>
+ * This is used to run manual validations (i.e. the user selects the Validate menu item), 
+ * or it is invoked programmatically by a third party through the ValidationFramework API.
+ * It is not used for the build based invocation.
+ * </p> 
  * @author karasiuk
  *
  */
-public class ValidationRunner implements IWorkspaceRunnable {
+public final class ValidationRunner implements IWorkspaceRunnable {
 	
 	private Map<IProject, Set<IResource>>		_projects;
 	private	ValType			_valType;
@@ -61,6 +69,31 @@
 		return me._valOperation;
 	}
 	
+	/**
+	 * Validate the selected file. This is a convenience method, it simply calls the more flexible 
+	 * validate with Map method. 
+	 * 
+	 * @param file
+	 *            The file to be validated.
+	 * 
+	 * @param valType
+	 *            The type of validation that has been requested.
+	 * 
+	 * @param monitor
+	 *            Progress monitor.
+	 * 
+	 * @param atomic
+	 *            Run as an atomic workspace operation?
+	 */
+	public static ValOperation validate(IFile file, ValType valType, IProgressMonitor monitor, boolean atomic) throws CoreException{
+	    final Map<IProject, Set<IResource>> map = new HashMap<IProject, Set<IResource>>(1);
+	      
+	    Set<IResource> set = new HashSet<IResource>(1);
+	    set.add(file);
+	    map.put(file.getProject(), set);
+	    return validate(map, valType, monitor, atomic);		
+	}
+	
 	private ValidationRunner(Map<IProject, Set<IResource>> projects, ValType valType){
 		_projects = projects;
 		_valType = valType;
@@ -91,14 +124,19 @@
 				
 		for (Map.Entry<IProject, Set<IResource>> me : _projects.entrySet()){
 			if (monitor.isCanceled()){
-				_valOperation.getResult().setCanceled(true);
+				_valOperation.setCanceled(true);
 				return _valOperation;
 			}
 			IProject project = me.getKey();
 			manager.accept(startingVisitor, project, _valType, _valOperation, monitor);
 			for (IResource resource : me.getValue()){
-				manager.validate(project, resource, IResourceDelta.NO_CHANGE, _valType, 
-					IncrementalProjectBuilder.AUTO_BUILD, _valOperation, monitor);
+				try {
+					manager.validate(project, resource, IResourceDelta.NO_CHANGE, _valType, 
+							IncrementalProjectBuilder.AUTO_BUILD, _valOperation, monitor);
+				}
+				catch (ResourceUnavailableError error){
+					// if the resource is no longer available, we can't validate it, so we should just move on. 
+				}
 			}
 			manager.accept(finishedVisitor, project, _valType, _valOperation, monitor);
 		}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidatorExtensionReader.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidatorExtensionReader.java
index 3a4975e..c897cfc 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidatorExtensionReader.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidatorExtensionReader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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
@@ -42,17 +42,16 @@
  */
 public class ValidatorExtensionReader {
 	
-	private static ValidatorExtensionReader _me;
+	private static ValidatorExtensionReader _me = new ValidatorExtensionReader();
 	
-	public static ValidatorExtensionReader getDefault(){
-		if (_me == null)_me = new ValidatorExtensionReader();
+	public  static ValidatorExtensionReader getDefault(){
 		return _me;
 	}
 	
 	private ValidatorExtensionReader(){}
 	
 	/**
-	 * Read the extensions.
+	 * Process the v2 extensions, returning all the v2 validators.
 	 */
 	Collection<Validator> process() {
 		Map<String,Validator> map = new HashMap<String, Validator>(100);
@@ -61,8 +60,11 @@
 				
 		for (IExtension ext : extensionPoint.getExtensions()){
 			for (IConfigurationElement validator : ext.getConfigurationElements()){
-				Validator v = processValidator(validator, ext.getUniqueIdentifier(), ext.getLabel(), null);
-				if (v != null)map.put(v.getId(),v);
+				String id = ext.getUniqueIdentifier();
+				if (Tracing.isEnabled(id)){
+					Validator v = processValidator(validator, id, ext.getLabel(), null);
+					if (v != null)map.put(v.getId(),v);
+				}
 			}
 		}
 		
@@ -83,7 +85,16 @@
 					}
 					else {
 						for (IConfigurationElement exclude : validator.getChildren()){
-							FilterGroup fg = createFilterGroup(exclude);
+							FilterGroup fg = null;
+							try {
+								fg = createFilterGroup(exclude);
+							}
+							catch (Exception e){
+								ValidationPlugin.getPlugin().handleException(e);
+								IContributor contrib = validator.getContributor();
+								String message = NLS.bind(ValMessages.ErrConfig, contrib.getName());
+								ValidationPlugin.getPlugin().logMessage(IStatus.ERROR, message);								
+							}
 							if (fg != null && fg.isExclude()){
 								mergeExcludeGroup(v2, fg);
 							}
@@ -113,10 +124,16 @@
 		}
 		if (existing == null)v2.add(fg);
 		else {
-			for (FilterRule rule : fg.getRules()){
-				existing.add(rule);
-			}
-			v2.bumpChangeCountGroups();
+			List<FilterRule> rules = new LinkedList<FilterRule>();
+			for (FilterRule rule : existing.getRules())rules.add(rule);
+			
+			for (FilterRule rule : fg.getRules())rules.add(rule);
+			
+			FilterRule[] filterRules = new FilterRule[rules.size()];
+			rules.toArray(filterRules);
+			FilterGroup merged = FilterGroup.create(existing.isExclude(), filterRules);
+			
+			v2.replaceFilterGroup(existing, merged);
 		}
 	}
 	
@@ -183,7 +200,7 @@
 	}
 
 	/**
-	 * Answer the extension point for the validators.
+	 * Answer the extension point for the v2 validators.
 	 * 
 	 * @return null if there is a problem or no extensions.
 	 */
@@ -193,7 +210,8 @@
 	}
 
 	/**
-	 * Answer the extension point for adding exclusion filters.
+	 * Answer the extension point for adding exclusion filters. This is where another validator can
+	 * further restrict an existing validator.
 	 * 
 	 * @return null if there is a problem or no extensions.
 	 */
@@ -202,9 +220,6 @@
 		return registry.getExtensionPoint(ValidationPlugin.PLUGIN_ID, ExtensionConstants.excludeExtension);
 	}
 	
-	
-	
-
 	/**
 	 * Process a message element for the validator, by creating a MessageCategory for it.
 	 * 
@@ -245,31 +260,45 @@
 	 *         element.
 	 */
 	private FilterGroup createFilterGroup(IConfigurationElement group){
-		FilterGroup fg = FilterGroup.create(group.getName());
-		if (fg == null)return null;			
+		String name = group.getName();
+		if (!FilterGroup.isKnownName(name))return null; 
+		
 		
 		IConfigurationElement[] rules = group.getChildren(ExtensionConstants.rules);
 		// there should only be one
+		List<FilterRule> list = new LinkedList<FilterRule>();
 		for (int i=0; i<rules.length; i++){
 			IConfigurationElement[] r = rules[i].getChildren();
 			for(int j=0; j<r.length; j++){
-				processRule(fg, r[j]);
+				list.add(processRule(r[j]));
 			}
 		}
-		return fg;
+		FilterRule[] filterRules = new FilterRule[list.size()];
+		list.toArray(filterRules);
+		return FilterGroup.create(name, filterRules);
 	}
 
 	/**
 	 * Process a rule in one of the rule groups.
 	 * 
-	 * @param fg the filter group that we are building up 
 	 * @param rule a rule in the group, like fileext.
 	 */
-	private void processRule(FilterGroup fg, IConfigurationElement rule) {
-		FilterRule fr = FilterRule.create(rule.getName());
-		if (fr == null)throw new IllegalStateException(ValMessages.ErrFilterRule);
-		fr.setData(rule);
-		fg.add(fr);
+	private FilterRule processRule(IConfigurationElement rule) {
+		FilterRule fr = FilterRule.create(rule);
+		if (fr == null){
+			String contributor = ""; //$NON-NLS-1$
+			String name = ""; //$NON-NLS-1$
+			try {
+				contributor = rule.getDeclaringExtension().getContributor().getName();
+				name = rule.getName();
+			}
+			catch (Exception e){
+				// eat it
+			}
+			throw new IllegalStateException(ValMessages.ErrFilterRule + " : " + //$NON-NLS-1$
+					contributor	 + " : " + name); //$NON-NLS-1$
+		}
+		return fr;
 	}
 	
 	/**
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidatorMutable.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidatorMutable.java
new file mode 100644
index 0000000..d18b0c5
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ValidatorMutable.java
@@ -0,0 +1,258 @@
+package org.eclipse.wst.validation.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.validation.IMutableValidator;
+import org.eclipse.wst.validation.MessageSeveritySetting;
+import org.eclipse.wst.validation.Validator;
+import org.eclipse.wst.validation.Validator.V1;
+import org.eclipse.wst.validation.Validator.V2;
+import org.eclipse.wst.validation.internal.model.FilterGroup;
+
+/**
+ * The mutable fields that a user can change through the preference or property page.
+ * @author karasiuk
+ *
+ */
+public final class ValidatorMutable implements IAdaptable, IMutableValidator {
+	
+	private boolean _build;
+	private boolean	_manual;
+	private String _delegatingId;
+	
+	private int _changeCountGroups;
+	private int _changeCountMessages;
+	
+	private final String	_name;
+	private final String 	_sourceId;
+	private final boolean _isV1;
+	private final boolean _isV2;
+	private final ValidatorMetaData _vmd;
+	private final String _id;
+	private final int	_version;
+
+	private FilterGroup[] _groups;
+	private final Map<String, MessageSeveritySetting> _messageSettings;
+	private final String _validatorClassname;
+	
+	private final boolean 	_origBuild;
+	private final boolean 	_origManual;
+	private final String	_origDelegating;
+
+	public ValidatorMutable(Validator validator) {
+		_name = validator.getName();
+		_sourceId = validator.getSourceId();
+		_manual = validator.isManualValidation();
+		_build = validator.isBuildValidation();
+		V2 v2 = validator.asV2Validator();
+		_isV2 = v2 != null;
+		_delegatingId = validator.getDelegatingId();
+		
+		V1 v1 = validator.asV1Validator();
+		_isV1 = v1 != null;
+		_vmd = _isV1 ? v1.getVmd() : null;
+		_id = validator.getId();
+		
+		_origBuild = _build;
+		_origDelegating = _delegatingId;
+		_origManual = _manual;
+		_version = validator.getVersion();
+		_validatorClassname = validator.getValidatorClassname();
+		_messageSettings = new HashMap<String, MessageSeveritySetting>(10); 
+		for (Map.Entry<String, MessageSeveritySetting> me : validator.getMessageSettings().entrySet()){
+			_messageSettings.put(me.getKey(), me.getValue().copy());
+		}
+		
+		if (v2 != null){
+			FilterGroup[] groups = v2.getGroups();
+			_groups = new FilterGroup[groups.length];
+			System.arraycopy(groups, 0, _groups, 0, groups.length);
+		}
+	}
+
+	public ValidatorMutable(ValidatorMutable val) {
+		_build = val._build;
+		_delegatingId = val._delegatingId;
+		FilterGroup[] groups = val.getGroups();
+		_groups = new FilterGroup[groups.length];
+		System.arraycopy(groups, 0, _groups, 0, groups.length);
+		
+		_id = val._id;
+		_isV1 = val._isV1;
+		_isV2 = val._isV2;
+		_manual = val._manual;
+		_messageSettings = new HashMap<String, MessageSeveritySetting>(10); 
+		for (Map.Entry<String, MessageSeveritySetting> me : val.getMessageSettings().entrySet()){
+			_messageSettings.put(me.getKey(), me.getValue().copy());
+		}
+
+		_name = val._name;
+		_origBuild = val._origBuild;
+		_origDelegating = val._origDelegating;
+		_origManual = val._origManual;
+		_sourceId = val._sourceId;
+		_validatorClassname = val._validatorClassname;
+		_version = val._version;
+		_vmd = val._vmd;
+	}
+
+	public void setBuildValidation(boolean build) {
+		_build = build;		
+	}
+
+	public void setManualValidation(boolean manual) {
+		_manual = manual;
+	}
+
+	public String getName() {
+		return _name;
+	}
+
+	public boolean isManualValidation() {
+		return _manual;
+	}
+
+	public boolean isBuildValidation() {
+		return _build;
+	}
+
+	public boolean isV2Validator() {
+		return _isV2;
+	}
+
+	public String getDelegatingId() {
+		return _delegatingId;
+	}
+
+	/**
+	 * The caller of this method must not change the ValidatorMetaData.
+	 */
+	public ValidatorMetaData getVmd() {
+		return _vmd;
+	}
+
+	public boolean isV1Validator() {
+		return _isV1;
+	}
+
+	public String getId() {
+		return _id;
+	}
+
+	/**
+	 * Answer true if any of your settings have changed.
+	 */
+	public boolean isChanged() {
+		if (hasGlobalChanges())return true;
+		if (_changeCountGroups > 0 || _changeCountMessages > 0)return true;
+		return false;
+	}
+
+	public boolean hasGlobalChanges() {
+		if (_origBuild != _build)return true;
+		if (_origManual != _manual)return true;
+		if (!Misc.same(_origDelegating, _delegatingId))return true;
+		return false;
+	}
+
+	public int getVersion() {
+		return _version;
+	}
+
+	public void replaceFilterGroup(FilterGroup existing, FilterGroup merged) {
+		int i = find(existing);
+		if (i == -1)add(merged);  // this should never happen
+		else {
+			_groups[i] = merged;
+			bumpChangeCountGroups();
+		}
+	}
+	
+	public void remove(FilterGroup group) {
+		int i = find(group);
+		if (i == -1)return;
+		
+		FilterGroup[] groups = new FilterGroup[_groups.length-1];
+		if (i > 0)System.arraycopy(_groups, 0, groups, 0, i);
+		if (i < groups.length)System.arraycopy(_groups, i+1, groups, i, groups.length-i);
+		_groups = groups;
+		bumpChangeCountGroups();
+	}
+	
+	private int find(FilterGroup group) {
+		for (int i=0; i<_groups.length; i++)if (group == _groups[i])return i;
+		return -1;
+	}
+
+	public void add(FilterGroup fg) {
+		assert fg != null;
+		FilterGroup[] groups = new FilterGroup[_groups.length+1];
+		System.arraycopy(_groups, 0, groups, 0, _groups.length);
+		groups[_groups.length] = fg;
+		_groups = groups;
+		bumpChangeCountGroups();
+	}
+	
+	private void bumpChangeCountGroups(){
+		_changeCountGroups++;
+	}
+
+	public int getChangeCountGroups() {
+		return _changeCountGroups;
+	}
+	
+	public FilterGroup[] getGroups(){
+		return _groups;
+	}
+
+	public void setDelegatingId(String id) {
+		_delegatingId = id;	
+	}
+
+	public Map<String, MessageSeveritySetting> getMessageSettings() {
+		return _messageSettings;
+	}
+	
+	public void bumpChangeCountMessages(){
+		_changeCountMessages++;
+	}
+
+	public String getValidatorClassname() {
+		return _validatorClassname;
+	}
+
+	@SuppressWarnings("unchecked")
+	public Object getAdapter(Class adapter) {
+		return Platform.getAdapterManager().getAdapter(this, adapter);
+	}
+
+	public boolean sameConfig(Validator validator) {
+		if (validator == null)return false;
+		return hashCodeForConfig() == validator.hashCodeForConfig();
+	}
+
+	private int hashCodeForConfig() {
+		int h = 0;
+		if (_build)h += 101;
+		if (_delegatingId != null)h += _delegatingId.hashCode();
+		if (_manual)h += 201;
+		if (_messageSettings != null){
+			for (MessageSeveritySetting ms : _messageSettings.values())h += ms.hashCode();
+		}
+		if (_sourceId != null)h += _sourceId.hashCode();
+		h += _version;
+		if (_id != null)h += _id.hashCode();
+		for (FilterGroup fg : _groups)h += fg.hashCodeForConfig();
+		return h;
+	}
+
+	@Override
+	public String toString() {
+		return _name;
+	}
+
+
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterGroup.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterGroup.java
index f544156..6d20dd5 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterGroup.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterGroup.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * Copyright (c) 2005, 2009 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
@@ -23,11 +23,14 @@
 import org.eclipse.wst.validation.internal.Serializer;
 import org.eclipse.wst.validation.internal.ValMessages;
 
+/**
+ * An immutable group of filter rules.
+ * @author karasiuk
+ *
+ */
 public abstract class FilterGroup implements IAdaptable {
 	
-	/** A list of FilterRule's for this group. */
-	List<FilterRule> _rules = new LinkedList<FilterRule>();
-	FilterRule[] _rulesArray;
+	private final FilterRule[] _rules;
 	
 	/** The version number of the serialization (in case we ever need to change this) */
 	private static final int SerializationVersion = 1;
@@ -39,9 +42,9 @@
 	 * 
 	 * @return null if the name parameter isn't correct.
 	 */
-	public static FilterGroup create(String name) {
-		if (ExtensionConstants.include.equals(name))return new FilterIncludeGroup();
-		if (ExtensionConstants.exclude.equals(name))return new FilterExcludeGroup();
+	public static FilterGroup create(String name, FilterRule[] rules) {
+		if (ExtensionConstants.include.equals(name))return new FilterIncludeGroup(rules);
+		if (ExtensionConstants.exclude.equals(name))return new FilterExcludeGroup(rules);
 		return null;
 	}
 	
@@ -54,9 +57,14 @@
 	public static FilterGroup create(Deserializer des){
 		des.getInt(); // get the version
 		String type = des.getString();
-		FilterGroup fg = create(type);
-		if (fg != null)fg.load(des);
-		return fg;
+		
+		int numberRules = des.getInt();
+		List<FilterRule> list = new LinkedList<FilterRule>();
+		for (int i=0; i<numberRules; i++)list.add(FilterRule.create(des));
+		FilterRule[] rules = new FilterRule[list.size()];
+		list.toArray(rules);
+
+		return create(type, rules);
 	}
 
 	/**
@@ -64,42 +72,36 @@
 	 * 
 	 * @param exclude if true an exclusion group is returned, otherwise an inclusion group is returned.
 	 */
-	public static FilterGroup create(boolean exclude){
-		if (exclude) return new FilterExcludeGroup();
-		return new FilterIncludeGroup();
+	public static FilterGroup create(boolean exclude, FilterRule[] rules){
+		if (exclude) return new FilterExcludeGroup(rules);
+		return new FilterIncludeGroup(rules);
 	}
 
-	public void add(FilterRule fr) {
-		_rulesArray = null;
-		_rules.add(fr);
-	}
-	
 	/**
-	 * If you can, remove this rule from yourself.
-	 * 
-	 * @param fr the rule that is being removed
-	 * 
-	 * @return true if the rule was removed, and false if it was not. If you didn't include the rule in the
-	 * first place, false would be returned.
+	 * Answer true if this is a supported type of group.
+	 * @param name Type of group that is being tested.
+	 * @return
 	 */
-	public synchronized boolean remove(FilterRule fr){
-		if (_rules.remove(fr)){
-			_rulesArray =  null;
-			return true;
-		}
+	public static boolean isKnownName(String name) {
+		if (ExtensionConstants.include.equals(name))return true;
+		if (ExtensionConstants.exclude.equals(name))return true;
 		return false;
 	}
+
 	
-	public FilterRule[] getRules(){
-		FilterRule[] rules = _rulesArray;
-		if (rules == null){
-			rules = new FilterRule[_rules.size()];
-			_rules.toArray(rules);
-			_rulesArray = rules;
-		}
+	private FilterGroup(FilterRule[] rules){
+		_rules = rules;
+	}
+		
+	/**
+	 * The rules in the group.
+	 */
+	public final FilterRule[] getRules(){
+		FilterRule[] rules = new FilterRule[_rules.length];
+		System.arraycopy(_rules, 0, rules, 0, _rules.length);
 		return rules;
 	}
-	
+		
 	/**
 	 * Answer the internal type of group, e.g. "include" or "exclude".
 	 */
@@ -113,7 +115,11 @@
 		return Platform.getAdapterManager().getAdapter(this, adapter);
 	}
 	
-	public static class FilterIncludeGroup extends FilterGroup {
+	public static final class FilterIncludeGroup extends FilterGroup {
+		
+		private FilterIncludeGroup(FilterRule[] rules){
+			super(rules);
+		}
 
 		public String getType() {
 			return ExtensionConstants.include;
@@ -127,22 +133,18 @@
 			return true;
 		}
 		
-		protected FilterGroup create() {
-			return new FilterIncludeGroup();
-		}
-		
 	}
 	
 	
-	public static class FilterExcludeGroup extends FilterGroup {
+	public static final class FilterExcludeGroup extends FilterGroup {
+		
+		private FilterExcludeGroup(FilterRule[] rules){
+			super(rules);
+		}
 		public String getType() {
 			return ExtensionConstants.exclude;
 		}
 		
-		protected FilterGroup create() {
-			return new FilterExcludeGroup();
-		}
-		
 		public String getDisplayableType() {
 			return ValMessages.GroupExclude;
 		}
@@ -151,12 +153,7 @@
 			return true;
 		}		
 	}
-	
-	protected void load(Deserializer des) {
-		int rules = des.getInt();
-		for (int i=0; i<rules; i++)_rules.add(FilterRule.create(des));
-	}
-	
+		
 	/**
 	 * Save your settings into the serializer.
 	 * @param ser
@@ -164,7 +161,7 @@
 	public void save(Serializer ser){
 		ser.put(SerializationVersion);
 		ser.put(getType());
-		ser.put(_rules.size());
+		ser.put(_rules.length);
 		for (FilterRule rule : _rules)rule.save(ser);		
 	}
 
@@ -176,11 +173,10 @@
 	 * only the project level checks are performed.
 	 */
 	public boolean shouldValidate(IProject project, IResource resource, ContentTypeWrapper contentTypeWrapper) {
-		FilterRule[] rules = getRules();
 		boolean exclude = isExclude();
 		boolean include = isInclude();
 		int count = 0;
-		for (FilterRule rule : rules){
+		for (FilterRule rule : _rules){
 			if (resource != null){
 				Boolean match = rule.matchesResource(resource, contentTypeWrapper);
 				if (match != null)count++;
@@ -214,28 +210,44 @@
 		return false;
 	}
 	
-	protected abstract FilterGroup create();
-
-	/** Answer a deep copy of yourself. */
-	public FilterGroup copy() {
-		FilterGroup fg = create();
-		FilterRule[] rules = getRules();
-		fg._rulesArray = new FilterRule[rules.length];
-		for (int i=0; i<rules.length; i++){
-			fg._rulesArray[i] = rules[i].copy();
-			fg._rules.add(fg._rulesArray[i]);
-		}
-		return fg;
-	}
-
 	public int hashCodeForConfig() {
 		int h = 0;
 		if (isExclude())h += 13;
-		if (_rules != null){
-			for (FilterRule fr : _rules)h += fr.hashCodeForConfig();
-		}
+		for (FilterRule fr : _rules)h += fr.hashCodeForConfig();
 		return h;
 	}
-	
+
+	/**
+	 * Create a new group by adding a rule to an existing group.
+	 * @param baseGroup The group that holds the existing rules.
+	 * @param rule The new rule that is being added
+	 * @return
+	 */
+	public static FilterGroup addRule(FilterGroup baseGroup, FilterRule rule) {
+		List<FilterRule> list = new LinkedList<FilterRule>();
+		for (FilterRule r : baseGroup._rules)list.add(r);
+		list.add(rule);
+		
+		FilterRule[] rules = new FilterRule[list.size()];
+		list.toArray(rules);
+		return FilterGroup.create(baseGroup.isExclude(), rules);
+	}
+
+	/**
+	 * Create a new group by removing a rule from an existing group.
+	 * @param baseGroup The group that holds the existing rules.
+	 * @param rule The rule that is being removed
+	 * @return
+	 */
+	public static FilterGroup removeRule(FilterGroup baseGroup,	FilterRule rule) {
+		List<FilterRule> list = new LinkedList<FilterRule>();
+		for (FilterRule r : baseGroup._rules){
+			if (!r.equals(rule))list.add(r);
+		}
+		
+		FilterRule[] rules = new FilterRule[list.size()];
+		list.toArray(rules);
+		return FilterGroup.create(baseGroup.isExclude(), rules);
+	}	
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterRule.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterRule.java
index 0097cd5..04cf0c2 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterRule.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/FilterRule.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal.model;
 
+import java.util.regex.Pattern;
+
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
@@ -23,79 +25,105 @@
 import org.eclipse.wst.validation.internal.ContentTypeWrapper;
 import org.eclipse.wst.validation.internal.Deserializer;
 import org.eclipse.wst.validation.internal.ExtensionConstants;
-import org.eclipse.wst.validation.internal.PrefConstants;
 import org.eclipse.wst.validation.internal.Serializer;
 import org.eclipse.wst.validation.internal.Tracing;
 import org.eclipse.wst.validation.internal.ValMessages;
 import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
-import org.osgi.service.prefs.Preferences;
 
 /**
  * A rule that is used to filter out (or in) validation on a resource.
+ * The concrete classes are all immutable.
  * @author karasiuk
  *
  */
 public abstract class FilterRule implements IAdaptable {
 	
-	protected String _pattern;
+	protected final String _pattern;
+	
+	protected static final String PortableFileDelim = "/"; //$NON-NLS-1$
 	
 	/**
-	 * Create a rule based on an extension element.
-	 * @param name the extension element, it can be one of projectNature, facet, fileext, file or contentType
+	 * Create a rule based on a configuration element.
+	 * 
+	 * @param rule
+	 *            The configuration element, see the extension point for details.
 	 * @return null if there is a problem.
 	 */
-	public static FilterRule create(String name){
-		if (ExtensionConstants.Rule.fileext.equals(name))return new FileExt();
-		if (ExtensionConstants.Rule.projectNature.equals(name))return new ProjectNature();
-		if (ExtensionConstants.Rule.file.equals(name))return new File();
-		if (ExtensionConstants.Rule.contentType.equals(name))return new ContentType();
-		if (ExtensionConstants.Rule.facet.equals(name))return new Facet();
+	public static FilterRule create(IConfigurationElement rule){
+		String name = rule.getName();
+		if (ExtensionConstants.Rule.fileext.equals(name))return new FileExt(rule);
+		if (ExtensionConstants.Rule.projectNature.equals(name))return new ProjectNature(rule);
+		if (ExtensionConstants.Rule.file.equals(name))return File.createFile(rule);
+		if (ExtensionConstants.Rule.contentType.equals(name))return ContentType.createContentType(rule);
+		if (ExtensionConstants.Rule.facet.equals(name))return new Facet(rule);
+		if (ExtensionConstants.Rule.pattern.equals(name))return FilePattern.createFilePattern(rule);
 		return null;
 	}
 	
-	public static FilterRule create(Deserializer des) {
+	static FilterRule create(Deserializer des) {
 		String type = des.getString();
-		FilterRule fr = create(type);
-		if (fr != null)fr.load(des);
-		return fr;
+		if (ExtensionConstants.Rule.fileext.equals(type)){
+			String pattern = des.getString();
+			boolean caseSensitive = des.getBoolean();
+			return new FileExt(pattern, caseSensitive);
+		}
+		
+		if (ExtensionConstants.Rule.projectNature.equals(type)){
+			String pattern = des.getString();
+			return new ProjectNature(pattern);
+		}
+		
+		if (ExtensionConstants.Rule.file.equals(type)){
+			String pattern = des.getString();
+			boolean caseSensitive = des.getBoolean();
+			int fileType = des.getInt();
+			return new File(pattern, caseSensitive, fileType);
+		}
+		
+		if (ExtensionConstants.Rule.contentType.equals(type)){
+			String pattern = des.getString();
+			boolean exactMatch = des.getBoolean();
+			return new ContentType(pattern, exactMatch);
+		}
+		
+		if (ExtensionConstants.Rule.facet.equals(type)){
+			String pattern = des.getString();
+			return new Facet(pattern, null);
+		}
+		
+		if (ExtensionConstants.Rule.pattern.equals(type)){
+			String pattern = des.getString();
+			boolean caseSensitive = des.getBoolean();
+			return new FilePattern(pattern, caseSensitive);
+		}
+		return null;
 	}
 
 	
 	public static FilterRule createFile(String pattern, boolean caseSensitive, int type){
-		File ext = new File();
-		ext.setData(pattern);
-		ext.setCaseSensitive(caseSensitive);
-		ext.setType(type);
-		return ext;
+		return new File(pattern, caseSensitive, type);
 	}
 	
 	public static FilterRule createFileExt(String pattern, boolean caseSensitive){
-		FileExt ext = new FileExt();
-		ext.setData(pattern);
-		ext.setCaseSensitive(caseSensitive);
+		FileExt ext = new FileExt(pattern, caseSensitive);
 		return ext;
 	}
 	
 	public static FilterRule createFacet(String facetId){
-		Facet facet = new Facet();
-		facet.setData(facetId);
-		return facet;
+		return new Facet(facetId, null);
 	}
 	
 	public static FilterRule createProject(String projectNature){
-		ProjectNature pn = new ProjectNature();
-		pn.setData(projectNature);
-		return pn;
+		return new ProjectNature(projectNature);
 	}
 	
 	public static FilterRule createContentType(String contentType, boolean exactMatch){
-		ContentType ct = new ContentType();
-		ct.setData(contentType);
-		ct.setExactMatch(exactMatch);
-		return ct;
+		return new ContentType(contentType, exactMatch);
 	}
-	
-	public abstract void setData(IConfigurationElement rule);
+		
+	protected FilterRule(String pattern){
+		_pattern = pattern;
+	}
 
 	/** 
 	 * Answer true if the rule matches the resource, false if it doesn't, and
@@ -116,11 +144,7 @@
 	public Boolean matchesProject(IProject project){
 		return null;
 	}
-	
-	public void setData(String data){
-		_pattern = data;
-	}
-	
+		
 	public String toString() {
 		return getDisplayableType() + ": " + _pattern; //$NON-NLS-1$
 	}
@@ -140,7 +164,7 @@
 	/** Answer a type that can be displayed to an end user. */
 	public abstract String getDisplayableType();
 	
-	public boolean asBoolean(String value, boolean aDefault){
+	public static boolean asBoolean(String value, boolean aDefault){
 		if (value == null)return aDefault;
 		if (value.equals(ExtensionConstants.True))return true;
 		if (value.equals(ExtensionConstants.False))return false;
@@ -152,20 +176,45 @@
 		return Platform.getAdapterManager().getAdapter(this, adapter);
 	}
 	
-	public static class ProjectNature extends FilterRule {
-
-		
-		public FilterRule copy() {
-			ProjectNature rule = new ProjectNature();
-			rule._pattern = _pattern;
-			return rule;
+	public static abstract class FilterRuleCaseSensitive extends FilterRule {
+				
+		public FilterRuleCaseSensitive(String pattern, boolean caseSensitive) {
+			super(pattern);
+			_caseSensitive = caseSensitive;
 		}
 		
-		public void setData(IConfigurationElement rule) {
-			_pattern = rule.getAttribute(ExtensionConstants.RuleAttrib.id);
+		private final boolean _caseSensitive;
+				
+		@Override
+		public int hashCodeForConfig() {
+			int h =  super.hashCodeForConfig();
+			if (_caseSensitive)h += 401;
+			return h;
+		}
+				
+		@Override
+		public void save(Serializer ser) {
+			super.save(ser);
+			ser.put(_caseSensitive);
+		}
+						
+		public boolean isCaseSensitive() {
+			return _caseSensitive;
+		}
+				
+	}
+	
+	public static final class ProjectNature extends FilterRule {
+		
+		private ProjectNature(IConfigurationElement rule) {
+			super(rule.getAttribute(ExtensionConstants.RuleAttrib.id));
 			
 		}
 		
+		public ProjectNature(String projectNature) {
+			super(projectNature);
+		}
+
 		public String getDisplayableType() {
 			return ValMessages.RuleProjectNature;
 		}
@@ -185,28 +234,21 @@
 		
 	}
 	
-	public static class FileExt extends FilterRule {
+	public static final class FileExt extends FilterRuleCaseSensitive {
 		
-		private boolean _caseSensitive;
-		
-		public FilterRule copy() {
-			FileExt rule = new FileExt();
-			rule._pattern = _pattern;
-			rule._caseSensitive = _caseSensitive;
-			return rule;
+		private FileExt(IConfigurationElement rule){
+			super(rule.getAttribute(ExtensionConstants.RuleAttrib.ext), 
+				asBoolean(rule.getAttribute(ExtensionConstants.RuleAttrib.caseSensitive), false));
 		}
-		
+				
+		private FileExt(String pattern, boolean caseSensitive) {
+			super(pattern, caseSensitive);
+		}
+
 		public String getType() {
 			return ExtensionConstants.Rule.fileext;
 		}
 		
-		@Override
-		public int hashCodeForConfig() {
-			int h =  super.hashCodeForConfig();
-			if (_caseSensitive)h += 601;
-			return h;
-		}
-		
 		public String getDisplayableType() {
 			return ValMessages.RuleFileExt;
 		}
@@ -214,53 +256,17 @@
 		public String getName() {
 			return toString();
 		}
-
-		public void setData(IConfigurationElement rule) {
-			_pattern = rule.getAttribute(ExtensionConstants.RuleAttrib.ext);
-			_caseSensitive = asBoolean(rule.getAttribute(ExtensionConstants.RuleAttrib.caseSensitive), false);			
-		}
 		
 		public String toString() {
-			if (_caseSensitive)return NLS.bind(ValMessages.FileExtWithCase, getDisplayableType(), _pattern);
+			if (isCaseSensitive())return NLS.bind(ValMessages.FileExtWithCase, getDisplayableType(), _pattern);
 			return NLS.bind(ValMessages.FileExtWithoutCase, getDisplayableType(), _pattern);
 		}
 
 		public Boolean matchesResource(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 			String ext = resource.getFileExtension();
-			if (_caseSensitive)return _pattern.equals(ext);
+			if (isCaseSensitive())return _pattern.equals(ext);
 			return _pattern.equalsIgnoreCase(ext);
 		}
-
-		public boolean isCaseSensitive() {
-			return _caseSensitive;
-		}
-		
-		@Override
-		public void load(Preferences rid) {
-			_caseSensitive = rid.getBoolean(PrefConstants.caseSensitive, false);
-			super.load(rid);
-		}
-		
-		@Override
-		public void save(Preferences rid) {
-			rid.putBoolean(PrefConstants.caseSensitive, _caseSensitive);
-			super.save(rid);
-		}
-		
-		@Override
-		protected void load(Deserializer des) {
-			super.load(des);
-			_caseSensitive = des.getBoolean();
-		}
-		@Override
-		public void save(Serializer ser) {
-			super.save(ser);
-			ser.put(_caseSensitive);
-		}
-
-		public void setCaseSensitive(boolean caseSensitive) {
-			_caseSensitive = caseSensitive;
-		}		
 	}
 	
 	/**
@@ -268,78 +274,60 @@
 	 * @author karasiuk
 	 *
 	 */
-	public static class File extends FilterRule {
+	public static final class File extends FilterRuleCaseSensitive {
 		
-		private boolean _caseSensitive;
-		private String	_patternAsLowercase;
+		private final String	_patternAsLowercase;
 		
 		/** One of the FileTypeXX constants. */
-		private int		_type;
+		private final int		_type;
 		
 		public static final int FileTypeFile = 1;
 		public static final int FileTypeFolder = 2;
 		public static final int FileTypeFull = 3;
 		
-		private static final String PortableFileDelim = "/"; //$NON-NLS-1$
-		
-		public File(){			
+		private static File createFile(IConfigurationElement rule){
+			String pattern = rule.getAttribute(ExtensionConstants.RuleAttrib.name);
+			if (pattern == null)throw new IllegalStateException(ValMessages.ErrPatternAttrib);
+			String type = rule.getAttribute(ExtensionConstants.RuleAttrib.fileType);
+			if (type == null)throw new IllegalStateException(ValMessages.ErrTypeReq);
+			
+			int myType = -1;
+			if (ExtensionConstants.FileType.file.equals(type))myType = FileTypeFile;
+			else if (ExtensionConstants.FileType.folder.equals(type)){
+				myType = FileTypeFolder;
+				if (!pattern.endsWith(PortableFileDelim))pattern += PortableFileDelim;
+			}
+			else if (ExtensionConstants.FileType.full.equals(type))myType = FileTypeFull;
+			else {
+				Object[] parms = {type, ExtensionConstants.FileType.file, ExtensionConstants.FileType.folder, 
+					ExtensionConstants.FileType.full};
+				throw new IllegalStateException(NLS.bind(ValMessages.ErrType, parms));
+			}
+			boolean caseSensitive = asBoolean(rule.getAttribute(ExtensionConstants.RuleAttrib.caseSensitive), false);
+			return new File(pattern, caseSensitive, myType);
 		}
 		
-		public FilterRule copy() {
-			File rule = new File();
-			rule._pattern = _pattern;
-			rule._patternAsLowercase = _patternAsLowercase;
-			rule._caseSensitive = _caseSensitive;
-			rule._type = _type;
-			return rule;
+		private  File(String pattern, boolean caseSensitive, int type){			
+			super(pattern, caseSensitive);
+			_type = type;
+			_patternAsLowercase = pattern == null ? null : pattern.toLowerCase();
 		}
-		
+				
 		public String getType() {
 			return ExtensionConstants.Rule.file;
 		}
 		
-		@Override
-		public int hashCodeForConfig() {
-			int h =  super.hashCodeForConfig();
-			if (_caseSensitive)h += 401;
-			return h;
-		}
-		
 		public String getDisplayableType() {
 			if (_type == FileTypeFolder)return ValMessages.RuleFolder;
 			if (_type == FileTypeFull)return ValMessages.RuleFull;
 			return ValMessages.RuleFile;
 		}
 		
-		@Override
-		public void setData(String pattern) {
-			if (pattern != null)_patternAsLowercase = pattern.toLowerCase();
-			else _patternAsLowercase = null;
-			
-			_pattern = pattern;
-		}
-
 		public void setData(IConfigurationElement rule) {
-			setData(rule.getAttribute(ExtensionConstants.RuleAttrib.name));
-			if (_pattern == null)throw new IllegalStateException(ValMessages.ErrPatternAttrib);
-			_caseSensitive = asBoolean(rule.getAttribute(ExtensionConstants.RuleAttrib.caseSensitive), false);	
-			String type = rule.getAttribute(ExtensionConstants.RuleAttrib.fileType);
-			if (type == null)throw new IllegalStateException(ValMessages.ErrTypeReq);
-			if (ExtensionConstants.FileType.file.equals(type))_type = FileTypeFile;
-			else if (ExtensionConstants.FileType.folder.equals(type)){
-				_type = FileTypeFolder;
-				if (!_pattern.endsWith(PortableFileDelim))setData(_pattern + PortableFileDelim);
-			}
-			else if (ExtensionConstants.FileType.full.equals(type))_type = FileTypeFull;
-			else {
-				Object[] parms = {type, ExtensionConstants.FileType.file, ExtensionConstants.FileType.folder, 
-					ExtensionConstants.FileType.full};
-				throw new IllegalStateException(NLS.bind(ValMessages.ErrType, parms));
-			}
 		}
 		
 		public String toString() {
-			if (_caseSensitive)return NLS.bind(ValMessages.FileExtWithCase, getDisplayableType(), _pattern);
+			if (isCaseSensitive())return NLS.bind(ValMessages.FileExtWithCase, getDisplayableType(), _pattern);
 			return NLS.bind(ValMessages.FileExtWithoutCase, getDisplayableType(), _pattern);
 		}
 		
@@ -360,56 +348,33 @@
 			}
 			
 			if (name == null)return Boolean.FALSE;
-			if (_caseSensitive)return name.startsWith(_pattern);
+			if (isCaseSensitive())return name.startsWith(_pattern);
 			return name.toLowerCase().startsWith(_patternAsLowercase);
 		}
-		
-		@Override
-		public void load(Preferences rid) {
-			_caseSensitive = rid.getBoolean(PrefConstants.caseSensitive, false);
-			_type = rid.getInt(PrefConstants.fileType, -1);
-			super.load(rid);
-		}
-		
-		@Override
-		public void save(Preferences rid) {
-			rid.putBoolean(PrefConstants.caseSensitive, _caseSensitive);
-			rid.putInt(PrefConstants.fileType, _type);
-			super.save(rid);
-		}
-		
-		@Override
-		protected void load(Deserializer des) {
-			super.load(des);
-			_caseSensitive = des.getBoolean();
-			_type = des.getInt();
-		}
-		
+								
 		@Override
 		public void save(Serializer ser) {
 			super.save(ser);
-			ser.put(_caseSensitive);
 			ser.put(_type);
 		}
-
-		public void setCaseSensitive(boolean caseSensitive) {
-			_caseSensitive = caseSensitive;
-		}
-
-		public void setType(int type) {
-			_type = type;
-		}
 		
 	}
 	
-	public static class Facet extends FilterRule {
+	public static final class Facet extends FilterRule {
 		
-		public FilterRule copy() {
-			Facet rule = new Facet();
-			rule._pattern = _pattern;
-			return rule;
+		private final String _versionExpression;
+		
+		private Facet(IConfigurationElement rule){
+			super(rule.getAttribute(ExtensionConstants.RuleAttrib.id));
+			_versionExpression = rule.getAttribute(ExtensionConstants.RuleAttrib.version);
+			
 		}
-		
+				
+		public Facet(String facetId, String versionExpression) {
+			super(facetId);
+			_versionExpression = versionExpression;
+		}
+
 		public String getType() {
 			return ExtensionConstants.Rule.facet;
 		}
@@ -417,15 +382,12 @@
 		public String getDisplayableType() {
 			return ValMessages.RuleFacet;
 		}
-
-		public void setData(IConfigurationElement rule) {
-			_pattern = rule.getAttribute(ExtensionConstants.RuleAttrib.id);
-		}
 		
 		@Override
 		public Boolean matchesProject(IProject project) {
 			try {
-				return FacetedProjectFramework.hasProjectFacet(project, _pattern);
+				if (_versionExpression == null)return FacetedProjectFramework.hasProjectFacet(project, _pattern);
+				return FacetedProjectFramework.hasProjectFacet(project, _pattern, _versionExpression);
 			}
 			catch (CoreException e){
 				if (Tracing.isLogging())ValidationPlugin.getPlugin().handleException(e);
@@ -433,21 +395,43 @@
 			return Boolean.FALSE;
 		}
 		
-	}
-	
-	public static class ContentType extends FilterRule {
-		
-		private transient IContentType 	_type;
-		private boolean			_exactMatch = true;
-		
-		public FilterRule copy() {
-			ContentType rule = new ContentType();
-			rule._pattern = _pattern;
-			rule._type = _type;
-			rule._exactMatch = _exactMatch;
-			return rule;
+		@Override
+		public String toString() {
+			StringBuffer b = new StringBuffer(200);
+			b.append(getDisplayableType());
+			b.append(": "); //$NON-NLS-1$
+			b.append(_pattern);
+			
+			if (_versionExpression !=  null){
+				b.append(" ("); //$NON-NLS-1$
+				b.append(_versionExpression);
+				b.append(")"); //$NON-NLS-1$
+			}
+			return b.toString();
 		}
 		
+	}
+	
+	public static final class ContentType extends FilterRule {
+		
+		private final IContentType 	_type;
+		private final boolean		_exactMatch;
+		
+		private ContentType(String pattern, boolean exactMatch){
+			super(pattern);
+			_type = Platform.getContentTypeManager().getContentType(pattern);
+			_exactMatch = exactMatch;
+		}
+		
+		private static ContentType createContentType(IConfigurationElement rule){
+			String pattern = rule.getAttribute(ExtensionConstants.RuleAttrib.id);
+			boolean exactMatch = true;
+			String exact = rule.getAttribute(ExtensionConstants.RuleAttrib.exactMatch);
+			if (ExtensionConstants.False.equals(exact)) exactMatch = false;
+			
+			return new ContentType(pattern, exactMatch);
+		}
+				
 		public String getType() {
 			return ExtensionConstants.Rule.contentType;
 		}
@@ -462,25 +446,7 @@
 		public String getDisplayableType() {
 			return ValMessages.RuleContentType;
 		}
-		
-		@Override
-		public void load(Preferences rid) {
-			_exactMatch = rid.getBoolean(PrefConstants.exactMatch, true);
-			super.load(rid);
-		}
-		
-		@Override
-		public void save(Preferences rid) {
-			rid.putBoolean(PrefConstants.exactMatch, _exactMatch);
-			super.save(rid);
-		}
-		
-		@Override
-		protected void load(Deserializer des) {
-			super.load(des);
-			_exactMatch = des.getBoolean();
-		}
-		
+								
 		@Override
 		public void save(Serializer ser) {
 			super.save(ser);
@@ -488,19 +454,8 @@
 		}
 
 		public void setData(IConfigurationElement rule) {
-			setData(rule.getAttribute(ExtensionConstants.RuleAttrib.id));
-			boolean exactMatch = true;
-			String exact = rule.getAttribute(ExtensionConstants.RuleAttrib.exactMatch);
-			if (ExtensionConstants.False.equals(exact)) exactMatch = false;
-			setExactMatch(exactMatch);
 		}
-		
-		@Override
-		public void setData(String pattern) {
-			_pattern = pattern;
-			_type = Platform.getContentTypeManager().getContentType(pattern);
-		}
-		
+				
 		public Boolean matchesResource(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 			if (_type == null)return Boolean.FALSE;
 			if (resource instanceof IFile) {
@@ -517,19 +472,6 @@
 			}
 			return Boolean.FALSE;
 		}
-
-		/**
-		 * Should the content type match exactly, or should sub types be
-		 * included as well?
-		 * 
-		 * @param exactMatch
-		 *            If true this rule will only match this specific content
-		 *            type. If false this rule will match this content type and
-		 *            any of it's sub types.
-		 */
-		public void setExactMatch(boolean exactMatch) {
-			_exactMatch = exactMatch;
-		}
 		
 		@Override
 		public String toString() {
@@ -538,30 +480,44 @@
 		}
 		
 	}
+	
+	public static final class FilePattern extends FilterRuleCaseSensitive {
+		
+		private final Pattern _compiledPattern;
+		
+		private static FilePattern createFilePattern(IConfigurationElement rule){
+			String pattern = rule.getAttribute(ExtensionConstants.RuleAttrib.regex);
+			boolean caseSensitive = asBoolean(rule.getAttribute(ExtensionConstants.RuleAttrib.caseSensitive), false);
+			return new FilePattern(pattern, caseSensitive);
+		}
+		
+		private FilePattern(String pattern, boolean caseSensitive){
+			super(pattern, caseSensitive);
+			int flags = 0;
+			if (caseSensitive)flags = Pattern.CASE_INSENSITIVE;
+			Pattern compiledPattern = Pattern.compile(pattern, flags);				
+			_compiledPattern = compiledPattern;
+		}
 
-	/** Answer a deep copy of yourself. */
-	public abstract FilterRule copy();
+		@Override
+		public String getDisplayableType() {
+			// FIXME this should be replaced as soon as we are allowed to change the UI.
+			return ValMessages.RuleFile;
+		}
 
-	/**
-	 * Save yourself in the preference file.
-	 * @param rid
-	 */
-	public void save(Preferences rid) {
-		rid.put(PrefConstants.ruleType, getType());
-		rid.put(PrefConstants.pattern, getPattern());		
-	}
-
-	/**
-	 * @param rule
-	 */
-	public void load(Preferences rule) {
-		setData(rule.get(PrefConstants.pattern, null));		
+		@Override
+		public String getType() {
+			return ExtensionConstants.Rule.pattern;
+		}
+		
+		@Override
+		public Boolean matchesResource(IResource resource, ContentTypeWrapper wrapper) {
+			String name = PortableFileDelim + resource.getProjectRelativePath().toPortableString();
+			if (name == null)return Boolean.FALSE;
+			return _compiledPattern.matcher(name).matches();
+		}		
 	}
 	
-	protected void load(Deserializer des){
-		setData(des.getString());
-	}
-
 	/**
 	 * Save your settings into the serializer.
 	 * @param ser
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferences.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferences.java
index 274fa20..2989c2c 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferences.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferences.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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
@@ -12,9 +12,9 @@
 
 /**
  * This class represents the global Preferences as set on the Validation Preferences page. It doesn't
- * hold any of the individual validator settings, just the global check boxes.
+ * hold any of the individual validator settings, just the global check boxes. It is an immutable object.
  */
-public class GlobalPreferences {
+public final class GlobalPreferences {
 	
 	/** false - Default setting for the should all the validation be suspended setting. */ 
 	public static final boolean DefaultSuspend = false;
@@ -30,35 +30,65 @@
 	
 	/** 2 - The version of the framework meta data, if an explicit version isn't found. */
 	public static final int DefaultFrameworkVersion = 2;
+	
+	/** Bit masks for what has changed. */
+	public final static int ConfirmDialogMask = 1;
+	public final static int DisableAllValidationMask = 2;
+	public final static int OverrideMask = 4;
+	public final static int SaveAutomaticallyMask = 8;
+	public final static int StateTimeStampMask = 16;
+	public final static int VersionMask = 32;
+	
+	/**
+	 * The changes that could affect what gets validated.
+	 */
+	public final static int BuildChangeMask = DisableAllValidationMask | OverrideMask;
+	
 
-	private boolean _disableAllValidation = DefaultSuspend;
-	private boolean _saveAutomatically = DefaultAutoSave;
-	private boolean _confirmDialog = DefaultConfirm;
-	private boolean _override = DefaultOverride;
+	private final boolean _confirmDialog;
+	private final boolean _disableAllValidation;
+	private final boolean _override;
+	private final boolean _saveAutomatically;
 	
 	/** The plug-in state time stamp. */
-	private long	_stateTimeStamp;
+	private final long	_stateTimeStamp;
 	
 	/** The incoming version of the framework. This is used to determine if a migration is needed.*/
-	private int		_version;
-	
-	/** Has a setting changed that could effect which validators get called? */
-	private boolean	_configChange;
-	
+	private final int		_version;
+			
 	/**
 	 * The only valid way to get the global preferences is through the ValManager.
 	 * 
 	 * @see org.eclipse.wst.validation.internal.ValManager#getGlobalPreferences()
 	 */
-	public GlobalPreferences(){	}
+	public GlobalPreferences(GlobalPreferencesValues gp) {
+		_confirmDialog = gp.confirmDialog;
+		_disableAllValidation = gp.disableAllValidation;
+		_override = gp.override;
+		_saveAutomatically = gp.saveAutomatically;
+		_stateTimeStamp = gp.stateTimeStamp;
+		_version = gp.version;
+	}
 	
+	/**
+	 * Answer a copy of the values.
+	 * @return
+	 */
+	public GlobalPreferencesValues asValues(){
+		GlobalPreferencesValues gp = new GlobalPreferencesValues();
+		gp.confirmDialog = _confirmDialog;
+		gp.disableAllValidation = _disableAllValidation;
+		gp.override = _override;
+		gp.saveAutomatically = _saveAutomatically;
+		gp.stateTimeStamp = _stateTimeStamp;
+		gp.version = _version;
+		return gp;
+	}
+
 	public boolean getSaveAutomatically() {
 		return _saveAutomatically;
 	}
 
-	public void setSaveAutomatically(boolean saveAutomatically) {
-		_saveAutomatically = saveAutomatically;
-	}
 
 	/**
 	 * Answer if all validation has been disabled.
@@ -67,66 +97,37 @@
 		return _disableAllValidation;
 	}
 
-	public void setDisableAllValidation(boolean disableAllValidation) {
-		if (_disableAllValidation != disableAllValidation){
-			_configChange = true;
-			_disableAllValidation = disableAllValidation;
-		}
-	}
-
-	/**
-	 * Reset all the global preferences to their default settings. This doesn't reset
-	 * the individual validators.
-	 */
-	public void resetToDefault() {
-		setDisableAllValidation(DefaultSuspend);
-		_saveAutomatically = DefaultAutoSave;
-		_confirmDialog = DefaultConfirm;
-		setOverride(DefaultOverride);
-	}
-
 	public boolean getConfirmDialog() {
 		return _confirmDialog;
 	}
 
-	public void setConfirmDialog(boolean confirmDialog) {
-		_confirmDialog = confirmDialog;
-	}
-
 	public long getStateTimeStamp() {
 		return _stateTimeStamp;
 	}
 
-	public void setStateTimeStamp(long stateTimeStamp) {
-		_stateTimeStamp = stateTimeStamp;
-	}
-
 	/** Answer whether or not projects are allowed to override the global preferences. */
 	public boolean getOverride() {
 		return _override;
 	}
 
-	public void setOverride(boolean override) {
-		if (_override != override){
-			_configChange = true;
-			_override = override;
-		}
-	}
-
 	public int getVersion() {
 		return _version;
 	}
 
-	public void setVersion(int version) {
-		_version = version;
-	}
-
-	public boolean isConfigChange() {
-		return _configChange;
-	}
-
-	public void setConfigChange(boolean configChange) {
-		_configChange = configChange;
+	/**
+	 * Compare yourself to the other global preferences and answer a bitmask with the differences.
+	 * @param gp
+	 * @return bit mask of the changes. See the xxxMask constants for the values of the bits. A zero means that they are the same.
+	 */
+	public int compare(GlobalPreferences gp) {
+		int changes = 0;
+		if (_confirmDialog != gp.getConfirmDialog())changes |= ConfirmDialogMask;
+		if (_disableAllValidation != gp.getDisableAllValidation())changes |= DisableAllValidationMask;
+		if (_override != gp.getOverride())changes |= OverrideMask;
+		if (_saveAutomatically != gp.getSaveAutomatically())changes |= SaveAutomaticallyMask;
+		if (_stateTimeStamp != gp.getStateTimeStamp())changes |= StateTimeStampMask;
+		if (_version != gp.getVersion())changes |= VersionMask;
+		return changes;
 	}
 
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferencesValues.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferencesValues.java
new file mode 100644
index 0000000..cdf8345
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferencesValues.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.validation.internal.model;
+
+/**
+ * A mutable object that is used to initialize a GlobalPreference.
+ * @author karasiuk
+ *
+ */
+public class GlobalPreferencesValues {
+	public boolean disableAllValidation = GlobalPreferences.DefaultSuspend;
+	public boolean saveAutomatically = GlobalPreferences.DefaultAutoSave;
+	public boolean confirmDialog = GlobalPreferences.DefaultConfirm;
+	public boolean override = GlobalPreferences.DefaultOverride;
+	
+	/** The plug-in state time stamp. */
+	public long	stateTimeStamp;
+	
+	/** The incoming version of the framework. This is used to determine if a migration is needed.*/
+	public int		version;
+	
+	public GlobalPreferencesValues(){
+		
+	}
+
+}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ProjectPreferences.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ProjectPreferences.java
index a571dc6..dd26add 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ProjectPreferences.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ProjectPreferences.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 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
@@ -18,36 +18,43 @@
  * @author karasiuk
  *
  */
-public class ProjectPreferences {
+public final class ProjectPreferences {
+	/*
+	 * Before this object can be considered immutable, the mutable validators need to be addressed.
+	 */
 	/** false - Default setting for the "should all the validation be suspended" setting. */ 
 	public static final boolean DefaultSuspend = false;
 	
 	/** false - Default setting for letting projects override the global settings. */
 	public static final boolean DefaultOverride = false;
 	
-	private IProject	_project;
+	private final IProject	_project;
 
-	private boolean 	_override = DefaultOverride;
-	private boolean		_suspend = DefaultSuspend;
+	private final boolean 	_override;
+	private final boolean	_suspend;
 	
-	private Validator[]	_validators = new Validator[0];
+	private final Validator[]	_validators;
 	
 	public ProjectPreferences(IProject project){
 		_project = project;
+		_override = DefaultOverride;
+		_suspend  = DefaultSuspend;
+		_validators = new Validator[0];
+	}
+	
+	public ProjectPreferences(IProject project, boolean override, boolean suspend, Validator[] validators){
+		_project = project;
+		_override = override;
+		_suspend = suspend;
+		_validators = validators;
 	}
 	
 	public boolean getOverride() {
 		return _override;
 	}
-	public void setOverride(boolean override) {
-		_override = override;
-	}
 	public boolean getSuspend() {
 		return _suspend;
 	}
-	public void setSuspend(boolean suspend) {
-		_suspend = suspend;
-	}
 	
 	/**
 	 * Answer the validators that have been registered for this project.
@@ -57,10 +64,6 @@
 		return _validators;
 	}
 	
-	public void setValidators(Validator[] validators){
-		_validators = validators;
-	}
-	
 	public IProject getProject() {
 		return _project;
 	}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ValidatorHelper.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ValidatorHelper.java
index c3152b4..288f226 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ValidatorHelper.java
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/ValidatorHelper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * Copyright (c) 2005, 2009 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,7 @@
  *******************************************************************************/
 package org.eclipse.wst.validation.internal.model;
 
-import org.eclipse.wst.validation.Validator;
+import org.eclipse.wst.validation.internal.ValidatorMutable;
 
 /**
  * Implement some common validator methods, that don't need to be part of the API.
@@ -18,20 +18,13 @@
  * @author karasiuk
  *
  */
-public class ValidatorHelper {
+public final class ValidatorHelper {
 	
 	/**
 	 * Answer true if this validator already has an exclude filter.
-	 * 
-	 * @param v
-	 * @return
 	 */
-	public static boolean hasExcludeGroup(Validator.V2 v){
-		FilterGroup[] groups = v.getGroups();
-		for (int i=0; i<groups.length; i++){
-			if (groups[i].isExclude())return true;
-		}
-		return false;
-		
+	public static boolean hasExcludeGroup(ValidatorMutable v){
+		for (FilterGroup group : v.getGroups())if (group.isExclude())return true;
+		return false;		
 	}
 }
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/package.html b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/package.html
index 87823d6..caa9b25 100644
--- a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/package.html
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/package.html
@@ -10,7 +10,7 @@
 validation. If auto build is turned on then the validators are called
 when the user saves their file. If auto build is not turned on then
 the validators are called when the user starts a build.</p>
-<p>This framework was added to WTP in version 3.4.</p>
+<p>This framework was added to WTP in version 3.0.</p>
 <h3>Dependency Support</h3>
 <p>Sometimes resources depend on other resources, to determine whether they are 
 valid or not. An example would be that an XML resource could depend on a DTD. If at some 
@@ -28,7 +28,7 @@
 product.
 <p>In particular when the validate method returns, a
 <a href="ValidationResult.html">ValidationResult</a> must be returned, inside of 
-this result, all your dependencies need to be specified with the&nbsp;
+this result, all your dependencies need to be specified with the
 <a href="ValidationResult.html#setDependsOn(org.eclipse.core.resources.IResource[])">
 setDependsOn</a> method.<p>In addition to keeping the dependency information 
 up-to-date through the normal course of validation, direct access is also 
@@ -36,5 +36,16 @@
 <a href="ValidationFramework.html#getDependencyIndex()">getDependencyIndex</a> 
 method. The <a href="IDependencyIndex.html">IDependencyIndex</a> allows you to 
 directly manipulate the dependency information for a validator.
+<h3>Entry Points into the Validation Framework</h3>
+<p>Here are some of the points where the platform calls into the framework:</p>
+<ul>
+<li><b>Builder</b> - ValidationBuilder</li>
+<li><b>IFacetedProjectListener</b> - ValManager</li>
+<li><b>IJobChangeListener</b> - ValidationOperation, ValidationOperation.ValidationLauncherJob</li>
+<li><b>IProjectChangeListener</b> - ValManager</li>
+<li><b>IPropertyChangeListener</b> - ValidationConfiguration, DisabledResourceManager</li>
+<li><b>IResourceChangeListener</b> - EventManger</li>
+<li><b>IValChangedListener</b> - ValManager, DisabledValidatorManager</li>
+</ul>
 </body>
 </html>
diff --git a/plugins/org.eclipse.wst.validation/xsds/exclude.exsd b/plugins/org.eclipse.wst.validation/xsds/exclude.exsd
index 3ed9a96..92d7647 100644
--- a/plugins/org.eclipse.wst.validation/xsds/exclude.exsd
+++ b/plugins/org.eclipse.wst.validation/xsds/exclude.exsd
@@ -168,6 +168,7 @@
             <element ref="projectNature" minOccurs="0" maxOccurs="unbounded"/>
             <element ref="facet" minOccurs="0" maxOccurs="unbounded"/>
             <element ref="contentType" minOccurs="0" maxOccurs="unbounded"/>
+            <element ref="pattern" minOccurs="0" maxOccurs="unbounded"/>
          </sequence>
       </complexType>
    </element>
@@ -207,6 +208,30 @@
          </attribute>
       </complexType>
    </element>
+   <element name="pattern">
+      <annotation>
+         <documentation>
+            Holds a regualr expression, that matches the resource&apos;s project relative name.
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="regex" type="string" use="required">
+            <annotation>
+               <documentation>
+                  Holds a Java regular expression. See the class java.util.regex.Pattern for more details. This regular expression is matched against a resource&apos;s project relative path, after that path has been converted into a portable path.
+&lt;p&gt;The path will always start with a forward slash (/) so that folder names can be more easily matched.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="caseSensitive" type="boolean">
+            <annotation>
+               <documentation>
+                  If the file name is not case senstitive, then this needs to be set to false.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
 
    <annotation>
       <appinfo>
diff --git a/plugins/org.eclipse.wst.validation/xsds/validator.exsd b/plugins/org.eclipse.wst.validation/xsds/validator.exsd
index 7699671..fcb4818 100644
--- a/plugins/org.eclipse.wst.validation/xsds/validator.exsd
+++ b/plugins/org.eclipse.wst.validation/xsds/validator.exsd
@@ -225,6 +225,7 @@
             <element ref="projectNature" minOccurs="0" maxOccurs="unbounded"/>
             <element ref="facet" minOccurs="0" maxOccurs="unbounded"/>
             <element ref="contentType" minOccurs="0" maxOccurs="unbounded"/>
+            <element ref="pattern" minOccurs="0" maxOccurs="unbounded"/>
          </sequence>
       </complexType>
    </element>
@@ -238,6 +239,13 @@
                </documentation>
             </annotation>
          </attribute>
+         <attribute name="version" type="string">
+            <annotation>
+               <documentation>
+                  A version expression that can be used to futher qualify the match. If not specifed, then versions are not used as a criteria for selecting the facet. The syntax of this expression, is the same syntax that is used by the facet framework.
+               </documentation>
+            </annotation>
+         </attribute>
       </complexType>
    </element>
 
@@ -329,12 +337,46 @@
       </complexType>
    </element>
 
+   <element name="pattern">
+      <annotation>
+         <documentation>
+            Holds a regualr expression, that matches the resource&apos;s project relative name.
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="regex" type="string" use="required">
+            <annotation>
+               <documentation>
+                  Holds a Java regular expression. See the class java.util.regex.Pattern for more details. This regular expression is matched against a resource&apos;s project relative path, after that path has been converted into a portable path.
+&lt;p&gt;The path will always start with a forward slash (/) so that folder names can be more easily matched.
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="caseSensitive" type="boolean">
+            <annotation>
+               <documentation>
+                  If the file name is not case senstitive, then this needs to be set to false.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiInfo"/>
+      </appinfo>
+      <documentation>
+         Provisional API.
+      </documentation>
+   </annotation>
+
    <annotation>
       <appinfo>
          <meta.section type="since"/>
       </appinfo>
       <documentation>
-         WebTools 3.4.
+         WebTools 3.0.
       </documentation>
    </annotation>
 
@@ -361,15 +403,6 @@
       </documentation>
    </annotation>
 
-   <annotation>
-      <appinfo>
-         <meta.section type="apiInfo"/>
-      </appinfo>
-      <documentation>
-         Provisional API.
-      </documentation>
-   </annotation>
-
 
    <annotation>
       <appinfo>
diff --git a/plugins/org.eclipse.wst.validation/xsds/validatorgroup.exsd b/plugins/org.eclipse.wst.validation/xsds/validatorgroup.exsd
index ca2fb6f..df05cb1 100644
--- a/plugins/org.eclipse.wst.validation/xsds/validatorgroup.exsd
+++ b/plugins/org.eclipse.wst.validation/xsds/validatorgroup.exsd
@@ -95,7 +95,7 @@
          <meta.section type="since"/>
       </appinfo>
       <documentation>
-         WebTools 3.4
+         WebTools 3.0
       </documentation>
    </annotation>