[261032] Make more model objects immutable
diff --git a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/AdapterFactory.java b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/AdapterFactory.java
index 4337534..27b8765 100644
--- a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/AdapterFactory.java
+++ b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/AdapterFactory.java
@@ -20,7 +20,7 @@
 public class AdapterFactory implements IAdapterFactory {
 
 	public Object getAdapter(Object adaptableObject, Class adapterType) {
-		if (adapterType == IWorkbenchAdapter.class&& adaptableObject instanceof Validator.V2)return _valAdaptor;
+		if (adapterType == IWorkbenchAdapter.class && adaptableObject instanceof Validator.V2)return _valAdaptor;
 		if (adapterType == IWorkbenchAdapter.class && adaptableObject instanceof FilterGroup)return _fgAdaptor;
 		if (adapterType == IWorkbenchAdapter.class && adaptableObject instanceof FilterRule)return _ruleAdaptor;
 
diff --git a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/FilterDialog.java b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/FilterDialog.java
index 672b2d0..ebad40d 100644
--- a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/FilterDialog.java
+++ b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/FilterDialog.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
@@ -60,7 +60,7 @@
  * @author karasiuk
  *
  */
-public class FilterDialog extends Dialog {
+public final class FilterDialog extends Dialog {
 	
 	/** 
 	 * If we are doing project level filters this will point to the project. This is null if we are doing
@@ -86,7 +86,10 @@
 	private Button		_remove;
 	private ISelectionChangedListener	_nodeChangedListener;
 	
+	/** The currently selected group. If a rule is selected instead, then this will be null. */
 	private FilterGroup	_selectedGroup;
+	
+	/** The currently selected rule. If a group is selected instead, then this will be null. */
 	private FilterRule	_selectedRule;
 	
 	private Combo[]		_messageSev;
@@ -233,8 +236,9 @@
 				
 				FilterRule rule = nfr.getRule();
 				if (rule != null){
-					_selectedGroup.add(rule);
-					_v2.bumpChangeCountGroups();
+					FilterGroup newGroup = FilterGroup.addRule(_selectedGroup, rule);
+					_v2.replaceFilterGroup(_selectedGroup, newGroup);
+					_selectedGroup = newGroup;
 					refresh();
 				}
 			}
@@ -392,7 +396,8 @@
 	 */
 	private void addGroup(boolean exclude){
 		if (_v2 == null)return;
-		_v2.add(FilterGroup.create(exclude));
+		FilterRule[] rules = new FilterRule[0];
+		_v2.add(FilterGroup.create(exclude, rules));
 		refresh();
 		
 	}
@@ -407,13 +412,11 @@
 	 */
 	private void remove(){
 		if (_selectedRule != null){
-			FilterGroup[] groups = _v2.getGroups();
-			for (int i=0; i<groups.length; i++){
-				if (groups[i].remove(_selectedRule)){
-					_v2.bumpChangeCountGroups();
-					refresh();
-					return;
-				}
+			FilterGroup group = findGroup(_selectedRule);
+			if (group != null){
+				FilterGroup newGroup = FilterGroup.removeRule(group, _selectedRule);
+				_v2.replaceFilterGroup(group, newGroup);
+				refresh();
 			}
 		}
 		
@@ -424,6 +427,20 @@
 		}
 	}
 	
+	/**
+	 * Find the group in the current validator that has this rule.
+	 * @param rule The rule that we are searching for.
+	 * @return null if we can not find the group.
+	 */
+	private FilterGroup findGroup(FilterRule rule) {
+		for (FilterGroup group : _v2.getGroups()){
+			for (FilterRule fr : group.getRules()){
+				if (fr.equals(rule))return group;
+			}
+		}
+		return null;
+	}
+
 	private void updateButtons() {
 		if (_v2 != null){
 			_addGroupExclude.setEnabled(!ValidatorHelper.hasExcludeGroup(_v2));
diff --git a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/ResultsDialog.java b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/ResultsDialog.java
index c50e50e..3534eb7 100644
--- a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/ResultsDialog.java
+++ b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/dialog/ResultsDialog.java
@@ -29,6 +29,7 @@
 import org.eclipse.wst.validation.internal.ValPrefManagerGlobal;
 import org.eclipse.wst.validation.internal.ValidationResultSummary;
 import org.eclipse.wst.validation.internal.model.GlobalPreferences;
+import org.eclipse.wst.validation.internal.model.GlobalPreferencesValues;
 import org.eclipse.wst.validation.internal.ui.ValidationUIMessages;
 import org.eclipse.wst.validation.ui.internal.ValUIMessages;
 
@@ -62,9 +63,12 @@
 	@Override
 	protected void okPressed() {
 		if(_hideButton!=null) {
-			GlobalPreferences gp = ValManager.getDefault().getGlobalPreferences();
-			gp.setConfirmDialog(!_hideButton.getSelection());
-			ValPrefManagerGlobal.getDefault().savePreferences(gp);
+			ValManager vm = ValManager.getDefault();
+			GlobalPreferences gp = vm.getGlobalPreferences();
+			GlobalPreferencesValues gpv = gp.asValues();
+			gpv.confirmDialog = !_hideButton.getSelection();
+			int changes = vm.replace(gpv);
+			if (changes != 0)ValPrefManagerGlobal.getDefault().savePreferences();
 		}
 		super.okPressed();
 	}
diff --git a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/preferences/ValidationPreferencePage.java b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/preferences/ValidationPreferencePage.java
index 5906005..faaca1e 100644
--- a/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/preferences/ValidationPreferencePage.java
+++ b/plugins/org.eclipse.wst.validation.ui/vf2/org/eclipse/wst/validation/ui/internal/preferences/ValidationPreferencePage.java
@@ -64,6 +64,7 @@
 import org.eclipse.wst.validation.internal.ValPrefManagerGlobal;
 import org.eclipse.wst.validation.internal.ValidatorMetaData;
 import org.eclipse.wst.validation.internal.model.GlobalPreferences;
+import org.eclipse.wst.validation.internal.model.GlobalPreferencesValues;
 import org.eclipse.wst.validation.internal.ui.DelegatingValidatorPreferencesDialog;
 import org.eclipse.wst.validation.internal.ui.plugin.ValidationUIPlugin;
 import org.eclipse.wst.validation.ui.internal.HelpContextIds;
@@ -179,7 +180,7 @@
 		private Button _confirmButton;
 		private Label _listLabel;
 		private Table _validatorsTable;
-		private GlobalPreferences 	_globalPreferences = ValManager.getDefault().getGlobalPreferences();
+		private GlobalPreferencesValues 	_globalPreferences = ValManager.getDefault().getGlobalPreferences().asValues();
 		private GlobalConfiguration _globalConfig;
 		private Validator[] _validators;
 		
@@ -417,11 +418,11 @@
 			_confirmButton = new Button(validatorGroup, SWT.CHECK);
 			_confirmButton.setLayoutData(gd);
 			_confirmButton.setText(ValUIMessages.PrefPageConfirmDialog);
-			_confirmButton.setSelection(_globalPreferences.getConfirmDialog());
+			_confirmButton.setSelection(_globalPreferences.confirmDialog);
 			_confirmButton.addSelectionListener(new SelectionAdapter() {
 				public void widgetSelected(SelectionEvent e) {
 					// do not increment the _changeCount as this by itself should not trigger a build prompt
-					_globalPreferences.setConfirmDialog(_confirmButton.getSelection());
+					_globalPreferences.confirmDialog = _confirmButton.getSelection();
 					_confirmButton.setFocus();
 				}
 			});
@@ -434,11 +435,11 @@
 			_autoSave = new Button(validatorGroup, SWT.CHECK);
 			_autoSave.setLayoutData(gd);
 			_autoSave.setText(ValUIMessages.PrefPage_always_save);
-			_autoSave.setSelection(_globalPreferences.getSaveAutomatically());
+			_autoSave.setSelection(_globalPreferences.saveAutomatically);
 			_autoSave.addSelectionListener(new SelectionAdapter() {
 				public void widgetSelected(SelectionEvent e) {
 					// do not increment the _changeCount as this by itself should not trigger a build prompt
-					_globalPreferences.setSaveAutomatically(_autoSave.getSelection());
+					_globalPreferences.saveAutomatically = _autoSave.getSelection();
 					_autoSave.setFocus();
 				}
 			});
@@ -452,10 +453,9 @@
 			_suspend = new Button(validatorGroup, SWT.CHECK);
 			_suspend.setLayoutData(gd);
 			_suspend.setText(ValUIMessages.DISABLE_VALIDATION);
-			_suspend.setSelection(_globalPreferences.getDisableAllValidation());
+			_suspend.setSelection(_globalPreferences.disableAllValidation);
 			_suspend.addSelectionListener(new SelectionAdapter() {
 				public void widgetSelected(SelectionEvent e) {
-					_changeCount++;
 					_suspend.setFocus();
 					_validatorsTable.setEnabled(!_suspend.getSelection());
 					_enableAllButton.setEnabled(!_suspend.getSelection());
@@ -473,11 +473,10 @@
 			_override.setLayoutData(gd);
 			_override.setText(ValUIMessages.PREF_BUTTON_OVERRIDE);
 			_override.setEnabled(true);
-			_override.setSelection(_globalPreferences.getOverride());
+			_override.setSelection(_globalPreferences.override);
 			_override.addSelectionListener(new SelectionAdapter() {
 				public void widgetSelected(SelectionEvent e) {
-					_changeCount++;
-					_globalPreferences.setOverride(_override.getSelection());
+					_globalPreferences.override = _override.getSelection();
 					_override.setFocus();
 					
 				}
@@ -594,10 +593,10 @@
 		}
 
 		private void updateAllWidgets() throws InvocationTargetException {
-			_suspend.setSelection(_globalPreferences.getDisableAllValidation());
-			_autoSave.setSelection(_globalPreferences.getSaveAutomatically());
-			_confirmButton.setSelection(_globalPreferences.getConfirmDialog());
-			_override.setSelection(_globalPreferences.getOverride());
+			_suspend.setSelection(_globalPreferences.disableAllValidation);
+			_autoSave.setSelection(_globalPreferences.saveAutomatically);
+			_confirmButton.setSelection(_globalPreferences.confirmDialog);
+			_override.setSelection(_globalPreferences.override);
 			_validatorsTable.setEnabled(!_suspend.getSelection());
 			_enableAllButton.setEnabled(!_suspend.getSelection());
 			_disableAllButton.setEnabled(!_suspend.getSelection());
@@ -606,10 +605,14 @@
 		}
 
 		public boolean performOk() throws InvocationTargetException {
-			_globalPreferences.setDisableAllValidation(_suspend.getSelection());
-			_globalPreferences.setSaveAutomatically(_autoSave.getSelection());
+			_globalPreferences.disableAllValidation = _suspend.getSelection();
+			_globalPreferences.saveAutomatically = _autoSave.getSelection();
+			ValManager vm = ValManager.getDefault();
+			int changes = vm.replace(_globalPreferences);
+			if ((changes & GlobalPreferences.BuildChangeMask) != 0)_changeCount++;
+			
 			ValPrefManagerGlobal vpm = ValPrefManagerGlobal.getDefault();
-			vpm.savePreferences(_globalPreferences, _validators);
+			vpm.savePreferences(vm.getGlobalPreferences(), _validators);
 			saveV1Preferences();
 			
 			if (_changeCount > 0 && 
@@ -629,7 +632,7 @@
 				GlobalConfiguration gc = ConfigurationManager.getManager().getGlobalConfiguration();
 	//			gc.setCanProjectsOverride(overrideButton.getSelection());
 				
-				gc.setDisableAllValidation(_globalPreferences.getDisableAllValidation());
+				gc.setDisableAllValidation(_globalPreferences.disableAllValidation);
 				//pagePreferences.setEnabledValidators(getEnabledValidators());
 				
 				gc.setEnabledManualValidators(getEnabledManualValidators());				
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 e8948fb..0e9f544 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
@@ -922,8 +922,8 @@
 		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;
@@ -1292,6 +1292,11 @@
 		_validatorGroupIds = v2._validatorGroupIds;
 	}
 
+	public synchronized void replaceFilterGroup(FilterGroup existing, FilterGroup merged) {
+		remove(existing);
+		add(merged);
+	}
+
 }
 
 public String getSourceId() {
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 95462ed..ecd9317 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
@@ -21,6 +21,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
@@ -50,6 +51,7 @@
 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;
@@ -71,7 +73,7 @@
 	private Map<IProject, ProjectPreferences> _projectPreferences = 
 		Collections.synchronizedMap(new HashMap<IProject, ProjectPreferences>(50));
 	
-	private GlobalPreferences _globalPreferences;
+	private AtomicReference<GlobalPreferences> _globalPreferences = new AtomicReference<GlobalPreferences>();
 		
 	/**
 	 * This number increases each time any of the validation configurations change. It is used to determine
@@ -486,33 +488,31 @@
 	 * Answer the global validation preferences.
 	 */
 	public GlobalPreferences getGlobalPreferences(){
-		GlobalPreferences gp = _globalPreferences;
+		GlobalPreferences gp = _globalPreferences.get();
 		if (gp == null){
 			ValPrefManagerGlobal vpm = ValPrefManagerGlobal.getDefault();
-			gp = new GlobalPreferences();
-			vpm.loadGlobalPreferences(gp);
-			gp = setIfNotNullGlobalPreferences(gp);
+			gp = vpm.loadGlobalPreferences();
+			if (!_globalPreferences.compareAndSet(null, gp))gp = _globalPreferences.get();
 		}
-		return gp;		
+		return gp;
 	}
 	
 	/**
-	 * If the global preferences have not been set yet, set them now.
-	 * 
-	 * @param gp
-	 *            The global preferences to use if they have not already been
-	 *            set.
-	 * @return The current global preferences. If they were set before the
-	 *         original ones are returned. Otherwise the passed in ones are both
-	 *         saved and returned.
+	 * 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.
 	 */
-	private synchronized GlobalPreferences setIfNotNullGlobalPreferences(GlobalPreferences gp){
-		if (_globalPreferences == null){
-			_globalPreferences = gp;
+	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 _globalPreferences;
+		return changes;
 	}
-	
+		
 	public ProjectPreferences getProjectPreferences(IProject project) {
 		ProjectPreferences pp = getProjectPreferences2(project);
 		if (pp != null)return pp;
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 5bde05a..3808f30 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
@@ -24,6 +24,7 @@
 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;
@@ -181,16 +182,18 @@
 	 * 
 	 * @see ValManager#getGlobalPreferences()
 	 */
-	public void loadGlobalPreferences(GlobalPreferences gp) {
+	public GlobalPreferences loadGlobalPreferences() {
 		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));
+		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);
 	}
 	
 	/**
@@ -354,13 +357,13 @@
 	/**
 	 * Save the global preferences and the validators.
 	 */
-	public synchronized void savePreferences(GlobalPreferences gp){
+	public synchronized void savePreferences(){
 		try {
+			GlobalPreferences gp = ValManager.getDefault().getGlobalPreferences();
 			IEclipsePreferences prefs = ValidationFramework.getDefault().getPreferenceStore();
-			boolean isConfigChange = gp.isConfigChange();
 			savePreferences(prefs, gp);
 			prefs.flush();
-			updateListeners(isConfigChange);
+			updateListeners(true);
 		}
 		catch (BackingStoreException e){
 			ValidationPlugin.getPlugin().handleException(e);
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 5fdaf11..7e8a924 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
@@ -125,10 +125,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);
 		}
 	}
 	
@@ -205,7 +211,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.
 	 */
@@ -214,9 +221,6 @@
 		return registry.getExtensionPoint(ValidationPlugin.PLUGIN_ID, ExtensionConstants.excludeExtension);
 	}
 	
-	
-	
-
 	/**
 	 * Process a message element for the validator, by creating a MessageCategory for it.
 	 * 
@@ -257,27 +261,30 @@
 	 *         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) {
+	private FilterRule processRule(IConfigurationElement rule) {
 		FilterRule fr = FilterRule.create(rule);
 		if (fr == null){
 			String contributor = ""; //$NON-NLS-1$
@@ -291,7 +298,7 @@
 			}
 			throw new IllegalStateException(NLS.bind(ValMessages.ErrFilterRule, contributor, name));
 		}
-		fg.add(fr);
+		return fr;
 	}
 	
 	/**
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 e42bc53..156a498 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,40 +72,32 @@
 	 * 
 	 * @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);
+	/**
+	 * Answer true if this is a supported type of group.
+	 * @param name Type of group that is being tested.
+	 * @return
+	 */
+	public static boolean isKnownName(String name) {
+		if (ExtensionConstants.include.equals(name))return true;
+		if (ExtensionConstants.exclude.equals(name))return true;
+		return false;
+	}
+
+	
+	private FilterGroup(FilterRule[] rules){
+		_rules = rules;
 	}
 	
 	/**
-	 * 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.
+	 * The rules in the group. Callers of this method must not change this array in any way.
 	 */
-	public synchronized boolean remove(FilterRule fr){
-		if (_rules.remove(fr)){
-			_rulesArray =  null;
-			return true;
-		}
-		return false;
-	}
-	
 	public FilterRule[] getRules(){
-		FilterRule[] rules = _rulesArray;
-		if (rules == null){
-			rules = new FilterRule[_rules.size()];
-			_rules.toArray(rules);
-			_rulesArray = rules;
-		}
-		return rules;
+		return _rules;
 	}
 	
 	/**
@@ -113,7 +113,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 +131,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 +151,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 +159,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);		
 	}
 
@@ -214,28 +209,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];
-			fg._rules.add(rules[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.getRules())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.getRules()){
+			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/GlobalPreferences.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferences.java
index 274fa20..9b4c40e 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,74 @@
 	
 	/** 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(){
+		_confirmDialog = DefaultConfirm;
+		_disableAllValidation = DefaultSuspend;
+		_override  = DefaultOverride;
+		_saveAutomatically = DefaultAutoSave;
+		_stateTimeStamp = -1;
+		_version = -1;
+	}
 	
+	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 +106,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..b9ee1b0
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/model/GlobalPreferencesValues.java
@@ -0,0 +1,24 @@
+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..38705a1 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,7 +18,7 @@
  * @author karasiuk
  *
  */
-public class ProjectPreferences {
+public final class ProjectPreferences {
 	/** false - Default setting for the "should all the validation be suspended" setting. */ 
 	public static final boolean DefaultSuspend = false;
 	
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..b9d2654 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
@@ -18,7 +18,7 @@
  * @author karasiuk
  *
  */
-public class ValidatorHelper {
+public final class ValidatorHelper {
 	
 	/**
 	 * Answer true if this validator already has an exclude filter.