[227206] Optimize getting content types
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 dd11475..b05596c 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
@@ -29,6 +29,7 @@
 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.internal.ContentTypeWrapper;
 import org.eclipse.wst.validation.internal.DebugConstants;
 import org.eclipse.wst.validation.internal.DependencyIndex;
 import org.eclipse.wst.validation.internal.DisabledResourceManager;
@@ -172,8 +173,9 @@
 	public Validator[] getValidatorsFor(IResource resource, boolean isManual, boolean isBuild){
 		IProject project = resource.getProject();
 		List<Validator> list = new LinkedList<Validator>();
+		ContentTypeWrapper ctw = new ContentTypeWrapper();
 		for (Validator val : ValManager.getDefault().getValidators(project)){
-			if (val.shouldValidate(resource, isManual, isBuild))list.add(val);
+			if (val.shouldValidate(resource, isManual, isBuild, ctw))list.add(val);
 		}
 		
 		Validator[] result = new Validator[list.size()];
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 87e8393..77b626a 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
@@ -29,6 +29,7 @@
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.wst.validation.internal.ConfigurationManager;
+import org.eclipse.wst.validation.internal.ContentTypeWrapper;
 import org.eclipse.wst.validation.internal.ExtensionConstants;
 import org.eclipse.wst.validation.internal.MarkerManager;
 import org.eclipse.wst.validation.internal.Misc;
@@ -203,11 +204,13 @@
 	 * 
 	 * @return true if the resource should be validated.
 	 */
-	public boolean shouldValidate(IResource resource, boolean isManual, boolean isBuild){
+	public boolean shouldValidate(IResource resource, boolean isManual, boolean isBuild, 
+		ContentTypeWrapper contentTypeWrapper){
+		
 		if (isManual && !_manualValidation)return false;
 		if (isBuild && !_buildValidation)return false;
 		
-		return shouldValidate(resource);
+		return shouldValidate(resource, contentTypeWrapper);
 	}
 	
 	/**
@@ -219,14 +222,14 @@
 	 * 
 	 * @return true if the resource should be validated.
 	 */
-	public boolean shouldValidate(IResource resource, ValType valType){
+	public boolean shouldValidate(IResource resource, ValType valType, ContentTypeWrapper contentTypeWrapper){
 		if (Tracing.matchesExtraDetail(getId())){
 			Tracing.log("Validator-01: checking if " + getId() + " should validate " + resource); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 		if (valType == ValType.Manual && !_manualValidation)return false;
 		if (valType == ValType.Build && !_buildValidation)return false;
 		
-		boolean result = shouldValidate(resource);
+		boolean result = shouldValidate(resource, contentTypeWrapper);
 		if (Tracing.matchesExtraDetail(getId())){
 			Tracing.log("Validator-02: result = " + result); //$NON-NLS-1$
 		}
@@ -328,7 +331,7 @@
 		return null;
 	}
 	
-	protected abstract boolean shouldValidate(IResource resource);
+	protected abstract boolean shouldValidate(IResource resource, ContentTypeWrapper contentTypeWrapper);
 	protected abstract boolean shouldValidateProject(IProject project);
 			
 	public abstract String getId();
@@ -594,7 +597,7 @@
 	}
 
 	@Override
-	protected boolean shouldValidate(IResource resource) {
+	protected boolean shouldValidate(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 		return _vmd.isApplicableTo(resource);
 	}
 
@@ -898,11 +901,11 @@
 	 * 
 	 * @return true if the resource should be validated.
 	 */
-	protected boolean shouldValidate(IResource resource) {
+	protected boolean shouldValidate(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 		FilterGroup[] groups = getGroups();
 		IProject project = resource.getProject();
 		for (FilterGroup group : groups){
-			if (!group.shouldValidate(project, resource))return false;
+			if (!group.shouldValidate(project, resource, contentTypeWrapper))return false;
 		}
 		return true;
 	}
@@ -1080,8 +1083,9 @@
 	@Override
 	protected boolean shouldValidateProject(IProject project) {
 		FilterGroup[] groups = getGroups();
+		ContentTypeWrapper ctw = new ContentTypeWrapper();
 		for (FilterGroup group : groups){
-			if (!group.shouldValidate(project, null))return false;
+			if (!group.shouldValidate(project, null, ctw))return false;
 		}
 		return true;
 	}
diff --git a/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ContentTypeWrapper.java b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ContentTypeWrapper.java
new file mode 100644
index 0000000..2436c84
--- /dev/null
+++ b/plugins/org.eclipse.wst.validation/vf2/org/eclipse/wst/validation/internal/ContentTypeWrapper.java
@@ -0,0 +1,43 @@
+package org.eclipse.wst.validation.internal;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
+
+/**
+ * Since it can be expense to determine a content type, we provide a wrapper so that we only
+ * need to get it once, as we validate a resource.
+ * @author karasiuk
+ *
+ */
+public class ContentTypeWrapper {
+	
+	private IContentType _type;
+	private boolean 	_initialized;
+	
+	public IContentType getContentType(IFile file){
+		if (_initialized)return _type;
+		
+		IContentDescription cd = null;
+		try {
+			cd = file.getContentDescription();
+		}
+		catch (CoreException e){
+			try {
+				file.refreshLocal(IResource.DEPTH_ZERO, null);
+				cd = file.getContentDescription();
+			}
+			catch (CoreException e2){
+				if (Tracing.isLogging())ValidationPlugin.getPlugin().handleException(e2);
+			}
+		}
+		if (cd == null)return null;
+		_type = cd.getContentType();
+		_initialized = true;
+		return _type;
+	}
+
+}
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 32884ef..4e669f2 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
@@ -144,7 +144,7 @@
 		if (index.isDependedOn(resource)){
 			MarkerManager mm = MarkerManager.getDefault();
 			for (DependentResource dr : index.get(resource)){
-				if (dr.getValidator().shouldValidate(dr.getResource(), ValType.Build)){
+				if (dr.getValidator().shouldValidate(dr.getResource(), ValType.Build, new ContentTypeWrapper())){
 					mm.clearMarker(dr.getResource(), dr.getValidator()); 
 					_operation.getState().put(ValidationState.TriggerResource, resource);
 					ValManager.getDefault().validate(dr.getValidator(), _operation, dr.getResource(), 
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 7b5cb7d..a76c202 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
@@ -290,8 +290,9 @@
 			return v.hasValidator(folder);
 		}
 		else {
+			ContentTypeWrapper ctw = new ContentTypeWrapper();
 			for (Validator val : ValManager.getDefault().getValidators(resource.getProject())){
-				if (val.shouldValidate(resource, isManual, isBuild))return true;
+				if (val.shouldValidate(resource, isManual, isBuild, ctw))return true;
 			}			
 		}
 		return false;
@@ -624,10 +625,11 @@
 		
 		vp = new ValProperty();
 		vp.setConfigNumber(_configNumber);
+		ContentTypeWrapper ctw = new ContentTypeWrapper();
 		for (Validator val : getValidators(project)){
 			if (monitor.isCanceled())return;
 			if (!_projectManager.shouldValidate(val, project, valType))continue;
-			if (val.shouldValidate(resource, valType)){
+			if (val.shouldValidate(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
 				// this information for the session.
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 a984f1e..3fc39df 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
@@ -17,6 +17,7 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.Platform;
+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.Serializer;
@@ -174,14 +175,14 @@
 	 * @param resource the resource that is being validated. This can be null, in which case
 	 * only the project level checks are performed.
 	 */
-	public boolean shouldValidate(IProject project, IResource resource) {
+	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){
 			if (resource != null){
-				Boolean match = rule.matchesResource(resource);
+				Boolean match = rule.matchesResource(resource, contentTypeWrapper);
 				if (match != null)count++;
 				if (exclude && match != null && match)return false;
 				if (include && match != null && match)return true;
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 088107f..f4053b8 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
@@ -17,10 +17,10 @@
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.content.IContentDescription;
 import org.eclipse.core.runtime.content.IContentType;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework;
+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;
@@ -103,7 +103,7 @@
 	 * 
 	 * 	@param resource the resource that is being validated.
 	 */
-	public Boolean matchesResource(IResource resource){
+	public Boolean matchesResource(IResource resource, ContentTypeWrapper contentTypeWrapper){
 		return null;
 	}
 
@@ -225,7 +225,7 @@
 			return NLS.bind(ValMessages.FileExtWithoutCase, getDisplayableType(), _pattern);
 		}
 
-		public Boolean matchesResource(IResource resource) {
+		public Boolean matchesResource(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 			String ext = resource.getFileExtension();
 			if (_caseSensitive)return _pattern.equals(ext);
 			return _pattern.equalsIgnoreCase(ext);
@@ -321,7 +321,7 @@
 			return NLS.bind(ValMessages.FileExtWithoutCase, getDisplayableType(), _pattern);
 		}
 		
-		public Boolean matchesResource(IResource resource) {
+		public Boolean matchesResource(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 			String name = null;
 			switch (_type){
 			case FileTypeFile:
@@ -478,26 +478,19 @@
 			_type = Platform.getContentTypeManager().getContentType(pattern);
 		}
 		
-		public Boolean matchesResource(IResource resource) {
+		public Boolean matchesResource(IResource resource, ContentTypeWrapper contentTypeWrapper) {
 			if (_type == null)return Boolean.FALSE;
-			try {
-				if (resource instanceof IFile) {
-					IFile file = (IFile) resource;
-					IContentDescription cd = file.getContentDescription();
-					if (cd == null)return Boolean.FALSE;
-					IContentType ct = cd.getContentType();
-					if (ct == null)return Boolean.FALSE;
-					boolean match = false;
-					if (_exactMatch)match = ct.getId().equals(_type.getId());
-					else match = ct.isKindOf(_type);
-					
-					if (match && Tracing.isTraceMatches())
-						Tracing.log("FilterRule-01: ", toString() + " has matched " + resource); //$NON-NLS-1$ //$NON-NLS-2$
-					return match;
-				}
-			}
-			catch (CoreException e){
-				if(Tracing.isLogging())ValidationPlugin.getPlugin().handleException(e);
+			if (resource instanceof IFile) {
+				IFile file = (IFile) resource;
+				IContentType ct = contentTypeWrapper.getContentType(file);
+				if (ct == null)return Boolean.FALSE;
+				boolean match = false;
+				if (_exactMatch)match = ct.getId().equals(_type.getId());
+				else match = ct.isKindOf(_type);
+				
+				if (match && Tracing.isTraceMatches())
+					Tracing.log("FilterRule-01: ", toString() + " has matched " + resource); //$NON-NLS-1$ //$NON-NLS-2$
+				return match;
 			}
 			return Boolean.FALSE;
 		}