Bug 398252

[facelets] Validator is not fully overridable
diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.properties b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.properties
index 21fb12e..6f38f09 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.properties
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.properties
@@ -2,4 +2,5 @@
 EL_Hyperlinkdetector_name=Facelet EL Hyperlink Detector
 FaceletValidatorMarker=Facelet Validator
 Bundle-Name.0 = UI Plug-in
-Bundle-Vendor.0 = Eclipse.org
\ No newline at end of file
+Bundle-Vendor.0 = Eclipse.org
+extension-point.name = Facelet Validation Override Extension
\ No newline at end of file
diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.xml b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.xml
index 17c268d..05c6432 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.xml
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/plugin.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?eclipse version="3.2"?>
 <plugin>
+   <extension-point id="faceletValidator" name="%extension-point.name" schema="schema/faceletValidator.exsd"/>
    <extension
          point="org.eclipse.wst.sse.ui.editorConfiguration">
       <sourceViewerConfiguration
@@ -85,6 +86,14 @@
                <facet
                      id="jst.jsf" version="2.0">
                </facet>
+               <facet
+                     id="jst.jsf"
+                     version="2.1">
+               </facet>
+               <facet
+                     id="jst.jsf"
+                     version="2.2">
+               </facet>
             </rules>
          </include>
          <include>
@@ -144,4 +153,11 @@
             contentType="org.eclipse.wst.html.core.htmlsource">
       </modelQueryExtension>
    </extension>
+   <extension
+         point="org.eclipse.jst.jsf.facelet.ui.faceletValidator">
+      <validationStrategy
+            class="org.eclipse.jst.jsf.facelet.ui.internal.validation.DefaultFaceletValidationStrategy"
+            id="org.eclipse.jst.jsf.facelet.ui.defaultValidationStrategy">
+      </validationStrategy>
+   </extension>
 </plugin>
diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/schema/faceletValidator.exsd b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/schema/faceletValidator.exsd
new file mode 100644
index 0000000..70b36f1
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/schema/faceletValidator.exsd
@@ -0,0 +1,109 @@
+<?xml version='1.0' encoding='UTF-8'?>

+<!-- Schema file written by PDE -->

+<schema targetNamespace="org.eclipse.jst.jsf.facelet.ui" xmlns="http://www.w3.org/2001/XMLSchema">

+<annotation>

+      <appInfo>

+         <meta.schema plugin="org.eclipse.jst.jsf.facelet.ui" id="faceletValidator" name="faceletValidator"/>

+      </appInfo>

+      <documentation>

+         Optional extension to allow third-parties to replace the default facelet validator with their own.

+      </documentation>

+   </annotation>

+

+   <element name="extension">

+      <annotation>

+         <appInfo>

+            <meta.element />

+         </appInfo>

+      </annotation>

+      <complexType>

+         <sequence>

+            <element ref="validationStrategy"/>

+         </sequence>

+         <attribute name="point" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="id" type="string">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="name" type="string">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+               <appInfo>

+                  <meta.attribute translatable="true"/>

+               </appInfo>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

+   <element name="validationStrategy">

+      <complexType>

+         <attribute name="class" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+               <appInfo>

+                  <meta.attribute kind="java" basedOn="org.eclipse.jst.jsf.facelet.ui.internal.validation.AbstractFaceletValidationStrategy:"/>

+               </appInfo>

+            </annotation>

+         </attribute>

+         <attribute name="id" type="string" use="default" value="Enter default value">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="since"/>

+      </appInfo>

+      <documentation>

+         [Enter the first release in which this extension point appears.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="examples"/>

+      </appInfo>

+      <documentation>

+         [Enter extension point usage example here.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="apiinfo"/>

+      </appInfo>

+      <documentation>

+         Internal Provisional.

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="implementation"/>

+      </appInfo>

+      <documentation>

+         [Enter information about supplied implementation of this extension point.]

+      </documentation>

+   </annotation>

+

+

+</schema>

diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/FaceletUiPlugin.java b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/FaceletUiPlugin.java
index 15ed671..99b3386 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/FaceletUiPlugin.java
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/FaceletUiPlugin.java
@@ -1,8 +1,13 @@
 package org.eclipse.jst.jsf.facelet.ui.internal;
 
+import java.util.Map;
+
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.jst.jsf.designtime.internal.BasicExtensionFactory;
+import org.eclipse.jst.jsf.designtime.internal.BasicExtensionFactory.ExtensionData;
 import org.eclipse.jst.jsf.designtime.internal.view.model.TagRegistryFactory.TagRegistryFactoryException;
+import org.eclipse.jst.jsf.facelet.ui.internal.validation.AbstractFaceletValidationStrategy;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.osgi.framework.BundleContext;
 
@@ -20,6 +25,9 @@
     // The shared instance
     private static FaceletUiPlugin plugin;
 
+    private final Object extensionLock = new Object();
+    private BasicExtensionFactory<AbstractFaceletValidationStrategy>  faceletValidationStrategyExtension;
+
     /*
      * (non-Javadoc)
      * 
@@ -66,4 +74,15 @@
         getDefault().getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, "", e));
     }
 
+    
+    public Map<String, ExtensionData<AbstractFaceletValidationStrategy>> getValidationStrategy()
+    {
+        synchronized (this.extensionLock) {
+            if (this.faceletValidationStrategyExtension == null)
+            {
+                this.faceletValidationStrategyExtension = new BasicExtensionFactory<AbstractFaceletValidationStrategy>(this.getBundle(), "faceletValidator", "validationStrategy", false);
+            }
+            return this.faceletValidationStrategyExtension.getExtensions();
+        }
+    }
 }
diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/AbstractFaceletValidationStrategy.java b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/AbstractFaceletValidationStrategy.java
new file mode 100644
index 0000000..1a6253a
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/AbstractFaceletValidationStrategy.java
@@ -0,0 +1,134 @@
+package org.eclipse.jst.jsf.facelet.ui.internal.validation;

+

+import java.io.IOException;

+

+import org.eclipse.core.resources.IFile;

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.Platform;

+import org.eclipse.core.runtime.content.IContentType;

+import org.eclipse.core.runtime.content.IContentTypeManager;

+import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;

+import org.eclipse.jst.jsf.facelet.core.internal.util.ViewUtil;

+import org.eclipse.jst.jsf.validation.internal.IJSFViewValidator;

+import org.eclipse.jst.jsf.validation.internal.ValidationPreferences;

+import org.eclipse.jst.jsf.validation.internal.facelet.FaceletDiagnosticFactory;

+import org.eclipse.wst.sse.core.StructuredModelManager;

+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;

+import org.eclipse.wst.validation.internal.provisional.core.IReporter;

+import org.eclipse.wst.validation.internal.provisional.core.IValidator;

+

+

+/**

+ * Strategy that is delegated to from HTMLValidator to do the validation.  Allows third-parties to enhance

+ * or replace the existing strategy.

+ *

+ */

+public abstract class AbstractFaceletValidationStrategy {

+

+    /**

+     * return from getPriority to indicate no priority preference.  If any other strategy returns a value higher, then

+     * a validator returning a smaller value including 0 will be ignored.  If all return DONT_CARE then they will

+     * all be called.

+     */

+    public static final int DONT_CARE = 0;

+

+    /**

+     * The factory for diagnostics.

+     */

+    protected final FaceletDiagnosticFactory _diagnosticFactory = new FaceletDiagnosticFactory();

+

+    /**

+     * If not overriden, returns DONT_CARE.

+     * 

+     * @return a value indicating the override priority for this strategy.  If more than one validation strategy

+     * exists, then *only* the one that returns the highest positive value will be used.  If a strategy returns 0, then

+     * it is signallying that it does not care.  If no strategy returns a value greater than 0, then all strategies will

+     * be called. Negative values are currently reserved and strategies returning negative values will be treated as though

+     * they returned 0.

+     */

+    public int getPriority()

+    {

+        return DONT_CARE;

+    }

+

+//    /**

+//     * @param helper

+//     * @param reporter

+//     * @return status of this validation

+//     * @throws ValidationException

+//     */

+//    public IStatus validateInJob(final IValidationContext helper,

+//            final IReporter reporter) throws ValidationException

+//    {

+//        IStatus status = Status.OK_STATUS;

+//        try

+//        {

+//            validate(helper, reporter);

+//        }

+//        catch (final ValidationException e)

+//        {

+//            status = new Status(IStatus.ERROR, FaceletUiPlugin.PLUGIN_ID,

+//                    IStatus.ERROR, e.getLocalizedMessage(), e);

+//        }

+//        return status;

+//

+//    }

+

+    /**

+     * @param file

+     * @param reporter

+     * @param caller

+     */

+    public final void validateFile(final IFile file, final IReporter reporter, final IValidator caller)

+    {

+        final ValidationPreferences prefs = new ValidationPreferences(

+                JSFCorePlugin.getDefault().getPreferenceStore());

+        prefs.load();

+

+        IStructuredModel model = null;

+        try

+        {

+            model = StructuredModelManager.getModelManager().getModelForRead(

+                    file);

+

+            final ValidationReporter jsfReporter = new ValidationReporter(caller,

+                    reporter, file, prefs, model);

+            doValidate(file, jsfReporter);

+        }

+        catch (final CoreException e)

+        {

+            JSFCorePlugin.log("Error validating JSF", e);

+        }

+        catch (final IOException e)

+        {

+            JSFCorePlugin.log("Error validating JSF", e);

+        }

+        finally

+        {

+            if (null != model)

+            {

+                model.releaseFromRead();

+            }

+        }

+    }

+

+    /**

+     * @param file

+     * @param jsfReporter

+     */

+    protected abstract void doValidate(final IFile file, IJSFViewValidator.IValidationReporter jsfReporter);

+    

+    

+    /**

+     * @param model

+     * @return true validation should be executed against model

+     */

+    public boolean shouldValidate(final IFile model)

+    {

+        final IContentTypeManager manager = Platform.getContentTypeManager();

+        final IContentType contentType = manager

+                .getContentType("org.eclipse.wst.html.core.htmlsource");

+        return (contentType.isAssociatedWith(model.getName()))

+                && ViewUtil.isFaceletVDLFile(model);

+    }

+}

diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/DefaultFaceletValidationStrategy.java b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/DefaultFaceletValidationStrategy.java
new file mode 100644
index 0000000..2ff8549
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/DefaultFaceletValidationStrategy.java
@@ -0,0 +1,154 @@
+package org.eclipse.jst.jsf.facelet.ui.internal.validation;

+

+import java.io.IOException;

+import java.util.Collection;

+import java.util.Collections;

+import java.util.Set;

+

+import org.eclipse.core.resources.IFile;

+import org.eclipse.core.resources.IProject;

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IStatus;

+import org.eclipse.emf.common.util.Diagnostic;

+import org.eclipse.jst.jsf.common.runtime.internal.view.model.common.Namespace;

+import org.eclipse.jst.jsf.context.resolver.structureddocument.IDOMContextResolver;

+import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory;

+import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext;

+import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContextFactory;

+import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;

+import org.eclipse.jst.jsf.designtime.internal.view.model.ITagRegistry;

+import org.eclipse.jst.jsf.facelet.core.internal.util.ViewUtil;

+import org.eclipse.jst.jsf.validation.internal.IJSFViewValidator;

+import org.eclipse.jst.jsf.validation.internal.JSFValidatorFactory;

+import org.eclipse.wst.sse.core.StructuredModelManager;

+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;

+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;

+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr;

+import org.w3c.dom.Attr;

+import org.w3c.dom.Document;

+import org.w3c.dom.Element;

+

+/**

+ * The default validation strategy.

+ *

+ */

+public class DefaultFaceletValidationStrategy extends AbstractFaceletValidationStrategy {

+

+    @Override

+    protected void doValidate(final IFile file, final IJSFViewValidator.IValidationReporter jsfReporter) {

+        final IJSFViewValidator validator = JSFValidatorFactory

+                .createDefaultXMLValidator();

+

+        validator.validateView(file, jsfReporter);

+        validateFaceletHtml(file, jsfReporter);

+

+    }

+

+    /**

+     * @param file

+     * @param reporter

+     */

+    protected void validateFaceletHtml(final IFile file,

+            final IJSFViewValidator.IValidationReporter reporter)

+    {

+        IStructuredModel model = null;

+        try

+        {

+            model = StructuredModelManager.getModelManager().getModelForRead(

+                    file);

+

+            final IStructuredDocument structuredDoc = model

+                    .getStructuredDocument();

+

+            validateDocument(structuredDoc, reporter, file.getProject());

+        }

+        catch (final CoreException e)

+        {

+            JSFCorePlugin.log("Error validating JSF", e);

+        }

+        catch (final IOException e)

+        {

+            JSFCorePlugin.log("Error validating JSF", e);

+        }

+        finally

+        {

+            if (null != model)

+            {

+                model.releaseFromRead();

+            }

+        }

+    }

+

+    /**

+     * @param structuredDoc

+     * @param reporter

+     * @param project

+     */

+    protected void validateDocument(IStructuredDocument structuredDoc,

+            final IJSFViewValidator.IValidationReporter reporter, IProject project)

+    {

+        validateRoot(structuredDoc, reporter, project);

+    }

+

+    /**

+     * @param structuredDoc

+     * @param reporter

+     * @param project

+     */

+    protected void validateRoot(IStructuredDocument structuredDoc,

+            final IJSFViewValidator.IValidationReporter reporter, IProject project)

+    {

+        final IStructuredDocumentContext context = IStructuredDocumentContextFactory.INSTANCE

+                .getContext(structuredDoc, -1);

+        final IDOMContextResolver resolver = IStructuredDocumentContextResolverFactory.INSTANCE

+                .getDOMContextResolver(context);

+        final Document document = resolver.getDOMDocument();

+        Element rootElement = document.getDocumentElement();

+

+        if ("html".equals(rootElement.getNodeName()))

+        {

+            final Set<Attr> declaredNamespaces = ViewUtil

+                    .getDeclaredNamespaces(rootElement.getAttributes());

+            final ITagRegistry tagRegistry = ViewUtil

+                    .getHtmlTagRegistry(project);

+            final Collection<? extends Namespace> namespaces;

+            if (tagRegistry != null)

+            {

+                namespaces = tagRegistry.getAllTagLibraries();

+            }

+            else

+            {

+                // unexpected

+                namespaces = Collections.EMPTY_SET;

+                JSFCorePlugin.log(IStatus.ERROR, "Program Error: HTML tag registry not found"); //$NON-NLS-1$

+            }

+

+            for (final Attr attr : declaredNamespaces)

+            {

+                // only validate prefix declarations

+                if (attr.getPrefix() != null && attr instanceof IDOMAttr)

+                {

+                    final String declaredUri = attr.getValue();

+                    String findUri = null;

+                    SEARCH_NAMESPACES: for (final Namespace ns : namespaces)

+                    {

+                        if (ns.getNSUri().equals(declaredUri))

+                        {

+                            findUri = ns.getNSUri();

+                            break SEARCH_NAMESPACES;

+                        }

+                    }

+

+                    if (findUri == null)

+                    {

+                        final Diagnostic diag = _diagnosticFactory.create_CANNOT_FIND_FACELET_TAGLIB(declaredUri);

+                        final IDOMAttr domAttr = (IDOMAttr) attr;

+                        reporter.report(diag, domAttr.getValueRegionStartOffset(), domAttr

+                                .getValue().length());

+                    }

+                }

+            }

+        }

+    }

+

+}

diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/HTMLValidator.java b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/HTMLValidator.java
index b3df148..d20d718 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/HTMLValidator.java
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/src/org/eclipse/jst/jsf/facelet/ui/internal/validation/HTMLValidator.java
@@ -1,41 +1,19 @@
 package org.eclipse.jst.jsf.facelet.ui.internal.validation;
 
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.content.IContentType;
-import org.eclipse.core.runtime.content.IContentTypeManager;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
-import org.eclipse.emf.common.util.Diagnostic;
-import org.eclipse.jst.jsf.common.runtime.internal.view.model.common.Namespace;
-import org.eclipse.jst.jsf.context.resolver.structureddocument.IDOMContextResolver;
-import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory;
-import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext;
-import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContextFactory;
-import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
-import org.eclipse.jst.jsf.designtime.internal.view.model.ITagRegistry;
-import org.eclipse.jst.jsf.facelet.core.internal.util.ViewUtil;
+import org.eclipse.jst.jsf.designtime.internal.BasicExtensionFactory.ExtensionData;
 import org.eclipse.jst.jsf.facelet.ui.internal.FaceletUiPlugin;
-import org.eclipse.jst.jsf.validation.internal.IJSFViewValidator;
-import org.eclipse.jst.jsf.validation.internal.JSFValidatorFactory;
-import org.eclipse.jst.jsf.validation.internal.ValidationPreferences;
-import org.eclipse.jst.jsf.validation.internal.facelet.FaceletDiagnosticFactory;
-import org.eclipse.wst.sse.core.StructuredModelManager;
-import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
 import org.eclipse.wst.validation.AbstractValidator;
 import org.eclipse.wst.validation.ValidationResult;
 import org.eclipse.wst.validation.ValidationState;
@@ -45,236 +23,93 @@
 import org.eclipse.wst.validation.internal.provisional.core.IReporter;
 import org.eclipse.wst.validation.internal.provisional.core.IValidationContext;
 import org.eclipse.wst.validation.internal.provisional.core.IValidator;
-import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
 
 /**
  * The Facelet HTML file validator.
  * 
  * @author cbateman
- *
+ * 
  */
-public class HTMLValidator extends AbstractValidator implements IValidator
-{
-	private FaceletDiagnosticFactory _diagnosticFactory = new FaceletDiagnosticFactory();
+public class HTMLValidator extends AbstractValidator implements IValidator {
     /**
      * @param helper
      * @return no rule, null
      */
-    public ISchedulingRule getSchedulingRule(final IValidationContext helper)
-    {
+    public ISchedulingRule getSchedulingRule(final IValidationContext helper) {
         // no rule...
         return null;
     }
 
-    /**
-     * @param helper
-     * @param reporter
-     * @return status of this validation
-     * @throws ValidationException
-     */
-    public IStatus validateInJob(final IValidationContext helper,
-            final IReporter reporter) throws ValidationException
-    {
-        IStatus status = Status.OK_STATUS;
-        try
-        {
-            validate(helper, reporter);
-        }
-        catch (final ValidationException e)
-        {
-            status = new Status(IStatus.ERROR, FaceletUiPlugin.PLUGIN_ID,
-                    IStatus.ERROR, e.getLocalizedMessage(), e);
-        }
-        return status;
-
-    }
-
-    public void cleanup(final IReporter reporter)
-    {
+    public void cleanup(final IReporter reporter) {
         // do nothing
     }
 
     @Override
-	public ValidationResult validate(IResource resource, int kind, ValidationState state, IProgressMonitor monitor){
-		ValidationResult vr = new ValidationResult();
-		if (resource == null || !(resource instanceof IFile)) {
-			return vr;
-		}
-		IFile currentFile = (IFile) resource;
-        if (shouldValidate(currentFile)) {
-            validateFile(currentFile, vr.getReporter(monitor));
+    public ValidationResult validate(IResource resource, int kind, ValidationState state, IProgressMonitor monitor) {
+        final ValidationResult vr = new ValidationResult();
+        if (resource == null || !(resource instanceof IFile)) {
+            return vr;
         }
-		return vr;
-	}
+        IFile currentFile = (IFile) resource;
+        List<AbstractFaceletValidationStrategy> validationStrategies = getStrategies(currentFile.getProject());
+        for (AbstractFaceletValidationStrategy strategy : validationStrategies) {
+            if (strategy.shouldValidate(currentFile)) {
+                strategy.validateFile(currentFile, vr.getReporter(monitor), this);
+            }
+        }
+        return vr;
+    }
 
-    public void validate(final IValidationContext helper,
-            final IReporter reporter) throws ValidationException
-    {
+    public void validate(final IValidationContext helper, final IReporter reporter) throws ValidationException {
         final String[] uris = helper.getURIs();
         final IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
-        if (uris.length > 0)
-        {
+        if (uris.length > 0) {
             IFile currentFile = null;
 
-            for (int i = 0; i < uris.length && !reporter.isCancelled(); i++)
-            {
+            for (int i = 0; i < uris.length && !reporter.isCancelled(); i++) {
                 currentFile = wsRoot.getFile(new Path(uris[i]));
-                if (currentFile != null && currentFile.exists())
-                {
-                    if (shouldValidate(currentFile))
-                    {
-                        final int percent = (i * 100) / uris.length + 1;
-                        final IMessage message = new LocalizedMessage(
-                                IMessage.LOW_SEVERITY, percent + "% " + uris[i]);
-                        reporter.displaySubtask(this, message);
+                if (currentFile != null && currentFile.exists()) {
+                    List<AbstractFaceletValidationStrategy> validationStrategies = getStrategies(currentFile
+                            .getProject());
+                    for (AbstractFaceletValidationStrategy strategy : validationStrategies) {
+                        if (strategy.shouldValidate(currentFile)) {
+                            final int percent = (i * 100) / uris.length + 1;
+                            final IMessage message = new LocalizedMessage(IMessage.LOW_SEVERITY, percent + "% "
+                                    + uris[i]);
+                            reporter.displaySubtask(this, message);
 
-                        validateFile(currentFile, reporter);
-                    }
-                }
-            }
-        }
-
-    }
-
-    private void validateFile(final IFile file, final IReporter reporter)
-    {
-        final IJSFViewValidator validator = JSFValidatorFactory
-                .createDefaultXMLValidator();
-        final ValidationPreferences prefs = new ValidationPreferences(
-                JSFCorePlugin.getDefault().getPreferenceStore());
-        prefs.load();
-
-        IStructuredModel model = null;
-        try
-        {
-            model = StructuredModelManager.getModelManager().getModelForRead(
-                    file);
-
-            final ValidationReporter jsfReporter = new ValidationReporter(this,
-                    reporter, file, prefs, model);
-            validator.validateView(file, jsfReporter);
-            // TODO: break off into composite strategies
-            validateFaceletHtml(file, jsfReporter);
-        }
-        catch (final CoreException e)
-        {
-            JSFCorePlugin.log("Error validating JSF", e);
-        }
-        catch (final IOException e)
-        {
-            JSFCorePlugin.log("Error validating JSF", e);
-        }
-        finally
-        {
-            if (null != model)
-            {
-                model.releaseFromRead();
-            }
-        }
-    }
-
-    private void validateFaceletHtml(final IFile file,
-            final ValidationReporter reporter)
-    {
-        IStructuredModel model = null;
-        try
-        {
-            model = StructuredModelManager.getModelManager().getModelForRead(
-                    file);
-
-            final IStructuredDocument structuredDoc = model
-                    .getStructuredDocument();
-
-            validateDocument(structuredDoc, reporter, file.getProject());
-        }
-        catch (final CoreException e)
-        {
-            JSFCorePlugin.log("Error validating JSF", e);
-        }
-        catch (final IOException e)
-        {
-            JSFCorePlugin.log("Error validating JSF", e);
-        }
-        finally
-        {
-            if (null != model)
-            {
-                model.releaseFromRead();
-            }
-        }
-    }
-
-    private void validateDocument(IStructuredDocument structuredDoc,
-            final ValidationReporter reporter, IProject project)
-    {
-        validateRoot(structuredDoc, reporter, project);
-    }
-
-    private void validateRoot(IStructuredDocument structuredDoc,
-            ValidationReporter reporter, IProject project)
-    {
-        final IStructuredDocumentContext context = IStructuredDocumentContextFactory.INSTANCE
-                .getContext(structuredDoc, -1);
-        final IDOMContextResolver resolver = IStructuredDocumentContextResolverFactory.INSTANCE
-                .getDOMContextResolver(context);
-        final Document document = resolver.getDOMDocument();
-        Element rootElement = document.getDocumentElement();
-
-        if ("html".equals(rootElement.getNodeName()))
-        {
-            final Set<Attr> declaredNamespaces = ViewUtil
-                    .getDeclaredNamespaces(rootElement.getAttributes());
-            final ITagRegistry tagRegistry = ViewUtil
-                    .getHtmlTagRegistry(project);
-            final Collection<? extends Namespace> namespaces;
-            if (tagRegistry != null)
-            {
-                namespaces = tagRegistry.getAllTagLibraries();
-            }
-            else
-            {
-                // unexpected
-                namespaces = Collections.EMPTY_SET;
-                JSFCorePlugin.log(IStatus.ERROR, "Program Error: HTML tag registry not found"); //$NON-NLS-1$
-            }
-
-            for (final Attr attr : declaredNamespaces)
-            {
-                // only validate prefix declarations
-                if (attr.getPrefix() != null && attr instanceof IDOMAttr)
-                {
-                    final String declaredUri = attr.getValue();
-                    String findUri = null;
-                    SEARCH_NAMESPACES: for (final Namespace ns : namespaces)
-                    {
-                        if (ns.getNSUri().equals(declaredUri))
-                        {
-                            findUri = ns.getNSUri();
-                            break SEARCH_NAMESPACES;
+                            strategy.validateFile(currentFile, reporter, this);
                         }
                     }
-
-                    if (findUri == null)
-                    {
-                        final Diagnostic diag = _diagnosticFactory.create_CANNOT_FIND_FACELET_TAGLIB(declaredUri);
-                        final IDOMAttr domAttr = (IDOMAttr) attr;
-                        reporter.report(diag, domAttr.getValueRegionStartOffset(), domAttr
-                                .getValue().length());
-                    }
                 }
             }
         }
     }
-    
-    private boolean shouldValidate(final IFile model)
-    {
-        final IContentTypeManager manager = Platform.getContentTypeManager();
-        final IContentType contentType = manager
-                .getContentType("org.eclipse.wst.html.core.htmlsource");
-        return (contentType.isAssociatedWith(model.getName()))
-                && ViewUtil.isFaceletVDLFile(model);
+
+    private List<AbstractFaceletValidationStrategy> getStrategies(final IProject project) {
+        Map<String, ExtensionData<AbstractFaceletValidationStrategy>> possibleStrategies = FaceletUiPlugin.getDefault()
+                .getValidationStrategy();
+        List<AbstractFaceletValidationStrategy> strategies = new ArrayList<AbstractFaceletValidationStrategy>(
+                possibleStrategies.size());
+        int maxPriority = 0;
+        for (final Map.Entry<String, ExtensionData<AbstractFaceletValidationStrategy>> entry : possibleStrategies
+                .entrySet()) {
+            AbstractFaceletValidationStrategy instance = entry.getValue().getInstance(project);
+            if (instance != null) {
+
+                int priority = instance.getPriority();
+                if (priority > maxPriority) {
+                    strategies.clear();
+                    maxPriority = priority;
+                    strategies.add(instance);
+                }
+
+                if (priority == maxPriority) {
+                    strategies.add(instance);
+                }
+            }
+        }
+        return strategies;
     }
+
 }
diff --git a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/templates/templates.properties b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/templates/templates.properties
index 1b2b72b..397cad2 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/templates/templates.properties
+++ b/jsf/plugins/org.eclipse.jst.jsf.facelet.ui/templates/templates.properties
@@ -11,5 +11,5 @@
 New_Simple_Facelet_Composition_Page_Description=Creates a new Facelet page for use with a template.
 New_Facelet_Header.header=<?xml version="1.0" encoding="ISO-8859-1" ?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml">\n<body>\n<div style="width:100%;font-size:36px;line-height:48px;background-color:navy;color:white">My Facelet Application</div>\n</body>\n</html>\n
 New_Facelet_Footer.footer=<?xml version="1.0" encoding="ISO-8859-1" ?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml">\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />\n<title>Insert title here</title>\n</head>\n<body>\n<div style="background-color:navy;width:100%;color:white"></div>\n</body>\n</html>\n
-New_Facelet_Template.template=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" \n          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml"\n      xmlns:ui="http://java.sun.com/jsf/facelets">\n<head>\n  <title><ui:insert name="title">Default title</ui:insert></title>\n</head>\n\n<body>\n\n<div id="header">\n    <ui:insert name="header">\n    	Header area.  See comments below this line in the source.\n    	<!--  include your header file or uncomment the include below and create header.xhtml in this directory -->\n    	<!-- <ui:include src="header.xhtml"/> -->\n    </ui:insert>\n</div>\n\n\n<div id="content">\n  <ui:insert name="content">\n    	Content area.  See comments below this line in the source.\n    	<!--  include your content file or uncomment the include below and create content.xhtml in this directory -->\n	  	<!-- <div> -->\n    	<!-- <ui:include src="content.xhtml"/> -->  \n    	<!-- </div> -->\n  </ui:insert>\n</div>\n\n<div id="footer">\n  <ui:insert name="footer">\n    	Footer area.  See comments below this line in the source.\n    	<!--  include your header file or uncomment the include below and create footer.xhtml in this directory -->\n		<!--<ui:include src="footer.xhtml"/>  -->\n  </ui:insert>\n</div>\n\n</body>\n\n</html>\n
+New_Facelet_Template.template=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" \n          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml"\n      xmlns:ui="http://java.sun.com/jsf/facelets">\n<head>\n  <title><ui:insert name="title">Default title</ui:insert></title>\n</head>\n\n<body>\n<ui:debug hotkey="x" rendered="#{initParam['javax.faces.FACELETS_DEVELOPMENT']}"/>\n\n<div id="header">\n    <ui:insert name="header">\n    	Header area.  See comments below this line in the source.\n    	<!--  include your header file or uncomment the include below and create header.xhtml in this directory -->\n    	<!-- <ui:include src="header.xhtml"/> -->\n    </ui:insert>\n</div>\n\n\n<div id="content">\n  <ui:insert name="content">\n    	Content area.  See comments below this line in the source.\n    	<!--  include your content file or uncomment the include below and create content.xhtml in this directory -->\n	  	<!-- <div> -->\n    	<!-- <ui:include src="content.xhtml"/> -->  \n    	<!-- </div> -->\n  </ui:insert>\n</div>\n\n<div id="footer">\n  <ui:insert name="footer">\n    	Footer area.  See comments below this line in the source.\n    	<!--  include your header file or uncomment the include below and create footer.xhtml in this directory -->\n		<!--<ui:include src="footer.xhtml"/>  -->\n  </ui:insert>\n</div>\n\n</body>\n\n</html>\n
 New_Simple_Facelet_Composition_Page.composition=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" \n    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n\n<html xmlns="http://www.w3.org/1999/xhtml"\n	xmlns:ui="http://java.sun.com/jsf/facelets"\n	xmlns:h="http://java.sun.com/jsf/html"\n	xmlns:f="http://java.sun.com/jsf/core">\n\n<ui:composition template="">\n	<ui:define name="header">\n	    Add your header here or delete to use the default\n	</ui:define>\n	<ui:define name="content">\n	    Add your content here or delete to use the default\n	</ui:define>\n	<ui:define name="footer">\n	    Add your footer here or delete to use the default\n	</ui:define>\n</ui:composition>\n</html>