MYFACES-2938 Allow @JSFValidator and @JSFConverter to define custom tagHandler class
diff --git a/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFConverter.java b/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFConverter.java
index 915707b..a2338c0 100644
--- a/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFConverter.java
+++ b/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFConverter.java
@@ -80,4 +80,44 @@
      * @since 1.0.3
      */
     String serialuidtag() default "";
+    
+    /**
+     * The fully-qualified-name of a concrete converter class.
+     * <p>
+     * This attribute is only relevant when "name" is also set, ie the
+     * annotation is indicating that a converter is really being declared.
+     * <p>
+     * When this attribute is not defined then it is assumed that this
+     * annotated class is the actual converter class.
+     * <p>
+     * When this attribute is set to something other than the name of the
+     * annotated class then the specified class is the one that the JSF
+     * converter registration in faces-config.xml will refer to. And if that
+     * class does not exist in the classpath (which will normally be the
+     * case) then code-generation will be triggered to create it.
+     * <p>
+     * This attribute is not inheritable.
+     * <p>
+     * The doclet-annotation equivalent of this attribute is named "class".
+     * 
+     * @since 1.0.7
+     */
+    String clazz() default "";
+    
+    /**
+     * Indicate tag handler class used for this component on facelets.
+     * 
+     * @since 1.0.7
+     */
+    String tagHandler() default "";
+    
+    /**
+     * Indicate that the EL Expressions should be stored using 
+     * setValueExpression() method, instead evaluate them at build view
+     * time. Later the EL Expressions will be evaluated according to
+     * their needs
+     * 
+     * @since 1.0.7
+     */
+    boolean evaluateELOnExecution() default false;
 }
diff --git a/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFValidator.java b/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFValidator.java
index 60d43ed..253b4b5 100644
--- a/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFValidator.java
+++ b/maven2-plugins/myfaces-builder-annotations/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/annotation/JSFValidator.java
@@ -104,4 +104,21 @@
      * @since 1.0.3
      */
     String clazz() default "";
+    
+    /**
+     * Indicate tag handler class used for this component on facelets.
+     * 
+     * @since 1.0.7
+     */
+    String tagHandler() default "";
+    
+    /**
+     * Indicate that the EL Expressions should be stored using 
+     * setValueExpression() method, instead evaluate them at build view
+     * time. Later the EL Expressions will be evaluated according to
+     * their needs
+     * 
+     * @since 1.0.7
+     */
+    boolean evaluateELOnExecution() default false;
 }
diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConvertersMojo.java b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConvertersMojo.java
new file mode 100644
index 0000000..d56230c
--- /dev/null
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConvertersMojo.java
@@ -0,0 +1,439 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one

+ *  or more contributor license agreements.  See the NOTICE file

+ *  distributed with this work for additional information

+ *  regarding copyright ownership.  The ASF licenses this file

+ *  to you under the Apache License, Version 2.0 (the

+ *  "License"); you may not use this file except in compliance

+ *  with the License.  You may obtain a copy of the License at

+ * 

+ *  http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ *  Unless required by applicable law or agreed to in writing,

+ *  software distributed under the License is distributed on an

+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ *  KIND, either express or implied.  See the License for the

+ *  specific language governing permissions and limitations

+ *  under the License.

+ */

+package org.apache.myfaces.buildtools.maven2.plugin.builder;

+

+import java.io.File;

+import java.io.FileOutputStream;

+import java.io.IOException;

+import java.io.OutputStreamWriter;

+import java.io.Writer;

+import java.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+

+import org.apache.maven.plugin.AbstractMojo;

+import org.apache.maven.plugin.MojoExecutionException;

+import org.apache.maven.project.MavenProject;

+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;

+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;

+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.BuildException;

+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MavenPluginConsoleLogSystem;

+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils;

+import org.apache.velocity.Template;

+import org.apache.velocity.VelocityContext;

+import org.apache.velocity.app.VelocityEngine;

+import org.apache.velocity.context.Context;

+import org.apache.velocity.runtime.RuntimeConstants;

+import org.codehaus.plexus.util.IOUtil;

+import org.codehaus.plexus.util.StringUtils;

+

+import com.thoughtworks.qdox.JavaDocBuilder;

+

+/**

+ * Maven goal to generate java source code for Converter classes.

+ * 

+ * <p>It uses velocity to generate templates, and has the option to define custom templates.</p>

+ * <p>The executed template has the following variables available to it:</p>

+ * <ul>

+ *  <li>utils : Returns an instance of 

+ *  org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils, 

+ *  it contains some useful methods.</li>

+ *  <li>converter : Returns the current instance of

+ *   org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta</li>

+ * </ul>

+ * 

+ * 

+ * @since 1.0.8

+ * @version $Id: MakeConvertersMojo.java 942970 2010-05-11 00:36:14Z lu4242 $

+ * @requiresDependencyResolution compile

+ * @goal make-converters

+ * @phase generate-sources

+ */

+public class MakeConvertersMojo extends AbstractMojo

+{

+    /**

+     * Injected Maven project.

+     * 

+     * @parameter expression="${project}"

+     * @readonly

+     */

+    private MavenProject project;

+

+    /**

+     * Defines the directory where the metadata file (META-INF/myfaces-metadata.xml) is loaded.

+     * 

+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"

+     * @readonly

+     */

+    private File buildDirectory;

+

+    /**

+     * Injected name of file generated by earlier run of BuildMetaDataMojo goal.

+     * 

+     * @parameter

+     */

+    private String metadataFile = "META-INF/myfaces-metadata.xml";

+

+    /**

+     * The directory used to load templates into velocity environment.

+     * 

+     * @parameter expression="src/main/resources/META-INF"

+     */

+    private File templateSourceDirectory;

+

+    /**

+     * The directory where all generated files are created. This directory is added as a

+     * compile source root automatically like src/main/java is. 

+     * 

+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"

+     */

+    private File generatedSourceDirectory;

+

+    /**

+     * Only generate tag classes that contains that package prefix

+     * 

+     * @parameter

+     */

+    private String packageContains;

+

+    /**

+     *  Log and continue execution when generating converter classes.

+     *  <p>

+     *  If this property is set to false (default), errors when a converter class is generated stops

+     *  execution immediately.

+     *  </p>

+     * 

+     * @parameter

+     */

+    private boolean force;

+

+    /**

+     * Defines the jsf version (1.1 or 1.2), used to take the default templates for each version.

+     * <p> 

+     * If version is 1.1, the default templateConverterName is 'converterClass11.vm' and if version

+     * is 1.2 the default templateConverterName is 'converterClass12.vm'.

+     * </p>

+     * 

+     * @parameter

+     */

+    private String jsfVersion;

+    

+    /**

+     * Define the models that should be included when generate converter classes. If not set, the

+     * current model identified by the artifactId is used.

+     * <p>

+     * Each model built by build-metadata goal has a modelId, that by default is the artifactId of

+     * the project. Setting this property defines which objects tied in a specified modelId should

+     * be taken into account.  

+     * </p>

+     * <p>In this case, limit converter tag generation only to the components defined in the models 

+     * identified by the modelId defined. </p>

+     * <p>This is useful when you need to generate files that take information defined on other

+     * projects.</p>

+     * <p>Example:</p>

+     * <pre>

+     *    &lt;modelIds&gt;

+     *        &lt;modelId>model1&lt;/modelId&gt;

+     *        &lt;modelId>model2&lt;/modelId&gt;

+     *    &lt;/modelIds&gt;

+     * </pre>

+     * 

+     * @parameter

+     */

+    private List modelIds;

+

+    /**

+     * The name of the template used to generate converter classes. According to the value on 

+     * jsfVersion property the default if this property is not set could be converterClass11.vm (1.1) or

+     * converterClass12.vm (1.2)

+     * 

+     * @parameter 

+     */

+    private String templateConverterName;

+    

+    /**

+     * This param is used to search in this folder if some file to

+     * be generated exists and avoid generation and duplicate exception.

+     * 

+     * @parameter expression="src/main/java"

+     */    

+    private File mainSourceDirectory;

+    

+    /**

+     * This param is used to search in this folder if some file to

+     * be generated exists and avoid generation and duplicate exception.

+     * 

+     * @parameter

+     */        

+    private File mainSourceDirectory2;

+

+    /**

+     * Execute the Mojo.

+     */

+    public void execute() throws MojoExecutionException

+    {

+        // This command makes Maven compile the generated source:

+        // getProject().addCompileSourceRoot( absoluteGeneratedPath.getPath() );

+        

+        try

+        {

+            project.addCompileSourceRoot( generatedSourceDirectory.getCanonicalPath() );

+            

+            if (modelIds == null)

+            {

+                modelIds = new ArrayList();

+                modelIds.add(project.getArtifactId());

+            }

+            Model model = IOUtils.loadModel(new File(buildDirectory,

+                    metadataFile));

+            new Flattener(model).flatten();

+            generateConverters(model);

+        }

+        catch (IOException e)

+        {

+            throw new MojoExecutionException("Error generating converters", e);

+        }

+        catch (BuildException e)

+        {

+            throw new MojoExecutionException("Error generating converters", e);

+        }

+    }

+    

+    

+    private VelocityEngine initVelocity() throws MojoExecutionException

+    {

+        File template = new File(templateSourceDirectory, _getTemplateName());

+        

+        if (template.exists())

+        {

+            getLog().info("Using template from file loader: "+template.getPath());

+        }

+        else

+        {

+            getLog().info("Using template from class loader: META-INF/"+_getTemplateName());

+        }

+                

+        VelocityEngine velocityEngine = new VelocityEngine();

+                

+        try

+        {

+            velocityEngine.setProperty( "resource.loader", "file, class" );

+            velocityEngine.setProperty( "file.resource.loader.class",

+                    "org.apache.velocity.runtime.resource.loader.FileResourceLoader");

+            velocityEngine.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());

+            velocityEngine.setProperty( "class.resource.loader.class",

+                    "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );

+            velocityEngine.setProperty( "class.resource.loader.path", "META-INF");            

+            velocityEngine.setProperty( "velocimacro.library", "converterClassMacros11.vm");

+            velocityEngine.setProperty( "velocimacro.permissions.allow.inline","true");

+            velocityEngine.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");

+            velocityEngine.setProperty( "directive.foreach.counter.initial.value","0");

+            //velocityEngine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,

+            //    "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );

+            

+            velocityEngine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM,

+                    new MavenPluginConsoleLogSystem(this.getLog()));

+

+            velocityEngine.init();

+        }

+        catch (Exception e)

+        {

+            throw new MojoExecutionException("Error creating VelocityEngine", e);

+        }

+        

+        return velocityEngine;

+    }

+    

+

+    /**

+     * Generates parsed converters.

+     */

+    private void generateConverters(Model model) throws IOException,

+            MojoExecutionException

+    {

+        // Make sure generated source directory 

+        // is added to compilation source path 

+        //project.addCompileSourceRoot(generatedSourceDirectory.getCanonicalPath());

+        

+        //Init Qdox for extract code 

+        JavaDocBuilder builder = new JavaDocBuilder();

+        

+        List sourceDirs = project.getCompileSourceRoots();

+        

+        // need a File object representing the original source tree

+        for (Iterator i = sourceDirs.iterator(); i.hasNext();)

+        {

+            String srcDir = (String) i.next();

+            builder.addSourceTree(new File(srcDir));

+        }        

+        

+        //Init velocity

+        VelocityEngine velocityEngine = initVelocity();

+

+        VelocityContext baseContext = new VelocityContext();

+        baseContext.put("utils", new MyfacesUtils());

+        

+        for (Iterator it = model.getConverters().iterator(); it.hasNext();)

+        {

+            ConverterMeta converter = (ConverterMeta) it.next();

+            

+            if (converter.getClassName() != null)

+            {

+                File f = new File(mainSourceDirectory, StringUtils.replace(

+                    converter.getClassName(), ".", "/")+".java");

+                                

+                if (!f.exists() && canGenerateConverter(converter))

+                {

+                    if (mainSourceDirectory2 != null)

+                    {

+                        File f2 = new File(mainSourceDirectory2, StringUtils.replace(

+                                converter.getClassName(), ".", "/")+".java");

+                        if (f2.exists())

+                        {

+                            //Skip

+                            continue;

+                        }

+                    }

+                    getLog().info("Generating converter class:"+converter.getClassName());

+                    try

+                    {

+                        _generateConverter(velocityEngine, builder,converter,baseContext);

+                    }

+                    catch(MojoExecutionException e)

+                    {

+                        if (force)

+                        {

+                            getLog().error(e.getMessage());

+                        }

+                        else

+                        {

+                            //Stop execution throwing exception

+                            throw e;

+                        }

+                    }

+                }

+            }

+        }        

+    }

+    

+    public boolean canGenerateConverter(ConverterMeta converter)

+    {

+        if ( modelIds.contains(converter.getModelId())

+                && includePackage(converter))

+        {

+            return true;

+        }

+        else

+        {

+            return false;

+        }

+    }

+    

+    public boolean includePackage(ConverterMeta converter)

+    {

+        if (packageContains != null)

+        {

+            if (MyfacesUtils.getPackageFromFullClass(converter.getClassName()).startsWith(packageContains))

+            {

+                return true;

+            }

+            else

+            {

+                return false;

+            }

+        }

+        else

+        {

+            return true;

+        }        

+    }

+    

+    

+    /**

+     * Generates a parsed converter.

+     * 

+     * @param converter

+     *            the parsed converter metadata

+     */

+    private void _generateConverter(VelocityEngine velocityEngine,

+            JavaDocBuilder builder,

+            ConverterMeta converter, VelocityContext baseContext)

+            throws MojoExecutionException

+    {

+        Context context = new VelocityContext(baseContext);

+        context.put("converter", converter);

+        

+        Writer writer = null;

+        File outFile = null;

+

+        try

+        {

+            outFile = new File(generatedSourceDirectory, StringUtils.replace(

+                    converter.getClassName(), ".", "/")+".java");

+

+            if ( !outFile.getParentFile().exists() )

+            {

+                outFile.getParentFile().mkdirs();

+            }

+

+            writer = new OutputStreamWriter(new FileOutputStream(outFile));

+

+            Template template = velocityEngine.getTemplate(_getTemplateName());

+                        

+            template.merge(context, writer);

+

+            writer.flush();

+        }

+        catch (Exception e)

+        {

+            throw new MojoExecutionException(

+                    "Error merging velocity templates: " + e.getMessage(), e);

+        }

+        finally

+        {

+            IOUtil.close(writer);

+            writer = null;

+        }

+    }

+                

+    private String _getTemplateName()

+    {

+        if (templateConverterName == null)

+        {

+            if (_is12())

+            {

+                return "converterClass12.vm";

+            }

+            else

+            {

+                return "converterClass11.vm";

+            }

+        }

+        else

+        {

+            return templateConverterName;

+        }

+    }

+    

+    private boolean _is12()

+    {

+        return "1.2".equals(jsfVersion) || "12".equals(jsfVersion);

+    }

+

+}

diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java
index cb0bccd..59298b9 100644
--- a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java
@@ -49,9 +49,13 @@
     private String _tagClass;
     private String _tagSuperclass;
     private String _serialuidtag;
+    private String _tagHandler;
     
+    private Boolean _generatedComponentClass;
     private Boolean _generatedTagClass;
     private Boolean _configExcluded;
+    
+    private Boolean _evaluateELOnExecution;
 
     /**
      * Write an instance of this class out as xml.
@@ -59,13 +63,17 @@
     protected void writeXmlSimple(XmlWriter out)
     {
         super.writeXmlSimple(out);
+
         out.writeElement("converterId", _converterId);
         out.writeElement("bodyContent", _bodyContent);
         out.writeElement("tagClass", _tagClass);
         out.writeElement("tagSuperclass", _tagSuperclass);
+        out.writeElement("tagHandler", _tagHandler);
         out.writeElement("serialuidtag", _serialuidtag);
+        out.writeElement("generatedComponentClass", _generatedComponentClass);
         out.writeElement("generatedTagClass", _generatedTagClass);
         out.writeElement("configExcluded", _configExcluded);
+        out.writeElement("evaluateELOnExecution", _evaluateELOnExecution);
     }
 
     /**
@@ -85,9 +93,12 @@
         digester.addBeanPropertySetter(newPrefix + "/bodyContent");
         digester.addBeanPropertySetter(newPrefix + "/tagClass");
         digester.addBeanPropertySetter(newPrefix + "/tagSuperclass");
+        digester.addBeanPropertySetter(newPrefix + "/tagHandler");
         digester.addBeanPropertySetter(newPrefix + "/serialuidtag");
+        digester.addBeanPropertySetter(newPrefix + "/generatedComponentClass");
         digester.addBeanPropertySetter(newPrefix + "/generatedTagClass");
         digester.addBeanPropertySetter(newPrefix + "/configExcluded");
+        digester.addBeanPropertySetter(newPrefix + "/evaluateELOnExecution");
     }
     
     public ConverterMeta()
@@ -106,8 +117,18 @@
     public void merge(ConverterMeta other)
     {
         super.merge(other);
+
         _bodyContent = ModelUtils.merge(this._bodyContent, other._bodyContent);
 
+        // inheritParentTag is true if the tag class to be generated for this
+        // artifact extends the tag class generated for the parent artifact.
+        // In this case, the tag for this class already inherits setter methods
+        // from its parent that handle all the inherited properties, so the
+        // tag class for this component just needs to handle its own properties.
+        //
+        // But when the tag class for this component does not extend the tag class
+        // for the parent component (because the parent component does not have
+        // a tag class) then we need to 
         boolean inheritParentTag = false;
         //check if the parent set a tag class
         if (other._tagClass != null)
@@ -124,8 +145,11 @@
                     other._tagSuperclass);            
         }
 
-        _converterId = ModelUtils.merge(this._converterId, other._converterId);
+        _tagHandler = ModelUtils.merge(this._tagHandler, other._tagHandler);
+        _evaluateELOnExecution = ModelUtils.merge(this._evaluateELOnExecution, other._evaluateELOnExecution);
         
+        _converterId = ModelUtils.merge(this._converterId, other._converterId);
+
         // TODO: _converterClassMOdifiers
         
         if (inheritParentTag)
@@ -158,7 +182,6 @@
             }
             _propertyTagList = null;
         }        
-
     }
 
     /**
@@ -239,6 +262,29 @@
         return _tagSuperclass;
     }
     
+    /**
+     * Specifies the class of the Facelets tag handler (component handler) for
+     * this component.
+     * <p>
+     * Note that a Facelets tag handler class is not needed for most components.
+     * </p>
+     * 
+     * @since 1.0.8
+     */
+    public void setTagHandler(String tagHandler)
+    {
+        _tagHandler = tagHandler;
+    }
+
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public String getTagHandler()
+    {
+        return _tagHandler;
+    }
+    
     public void setSerialuidtag(String serialuidtag)
     {
         _serialuidtag = serialuidtag;
@@ -249,6 +295,24 @@
         return _serialuidtag;
     }
     
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public void setGeneratedComponentClass(Boolean generatedComponentClass)
+    {
+        _generatedComponentClass = generatedComponentClass;
+    }
+
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public Boolean isGeneratedComponentClass()
+    {
+        return ModelUtils.defaultOf(_generatedComponentClass,false);
+    }
+
     public void setGeneratedTagClass(Boolean generatedTagClass)
     {
         _generatedTagClass = generatedTagClass;
@@ -269,8 +333,33 @@
         return ModelUtils.defaultOf(_configExcluded,false);
     }    
 
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public void setEvaluateELOnExecution(Boolean evaluateELOnExecution)
+    {
+        this._evaluateELOnExecution = evaluateELOnExecution;
+    }
+
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public Boolean isEvaluateELOnExecution()
+    {
+        return ModelUtils.defaultOf(_evaluateELOnExecution,false);
+    }
+
     //THIS METHODS ARE USED FOR VELOCITY TO GET DATA AND GENERATE CLASSES
-    
+
+    // A transient attribute that is computed on-demand from the model data
+    // but is not itself stored in the model.
+    //
+    // It holds a list of all the properties which need to be implemented
+    // on the tag class. This is a subset of the properties available on
+    // this component itself, and depends upon what the parent class
+    // of the generated tag already supports.
     private List _propertyTagList = null; 
     
     public Collection getPropertyTagList()
@@ -292,4 +381,28 @@
         return _propertyTagList;
     }
 
+    private List _propertyConverterList = null; 
+
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public Collection getPropertyConverterList()
+    {
+        if (_propertyConverterList == null)
+        {
+            _propertyConverterList = new ArrayList();
+            for (Iterator it = getPropertyList().iterator(); it.hasNext();)
+            {
+                PropertyMeta prop = (PropertyMeta) it.next();
+                if (!prop.isInherited().booleanValue() && prop.isGenerated().booleanValue())
+                {
+                    _propertyConverterList.add(prop);
+                }
+            }
+            
+        }
+        return _propertyConverterList;
+    }
+
 }
diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ValidatorMeta.java b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ValidatorMeta.java
index 2dc3a5a..5c8fe0e 100644
--- a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ValidatorMeta.java
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ValidatorMeta.java
@@ -40,10 +40,13 @@
     private String _tagClass;
     private String _tagSuperclass;
     private String _serialuidtag;
+    private String _tagHandler;
     
     private Boolean _generatedComponentClass;
     private Boolean _generatedTagClass;
     private Boolean _configExcluded;
+    
+    private Boolean _evaluateELOnExecution;
 
     /**
      * Write an instance of this class out as xml.
@@ -56,10 +59,12 @@
         out.writeElement("bodyContent", _bodyContent);
         out.writeElement("tagClass", _tagClass);
         out.writeElement("tagSuperclass", _tagSuperclass);
+        out.writeElement("tagHandler", _tagHandler);
         out.writeElement("serialuidtag", _serialuidtag);
         out.writeElement("generatedComponentClass", _generatedComponentClass);
         out.writeElement("generatedTagClass", _generatedTagClass);
         out.writeElement("configExcluded", _configExcluded);
+        out.writeElement("evaluateELOnExecution", _evaluateELOnExecution);
     }
 
     /**
@@ -79,10 +84,12 @@
         digester.addBeanPropertySetter(newPrefix + "/bodyContent");
         digester.addBeanPropertySetter(newPrefix + "/tagClass");
         digester.addBeanPropertySetter(newPrefix + "/tagSuperclass");
+        digester.addBeanPropertySetter(newPrefix + "/tagHandler");
         digester.addBeanPropertySetter(newPrefix + "/serialuidtag");
         digester.addBeanPropertySetter(newPrefix + "/generatedComponentClass");
         digester.addBeanPropertySetter(newPrefix + "/generatedTagClass");
         digester.addBeanPropertySetter(newPrefix + "/configExcluded");
+        digester.addBeanPropertySetter(newPrefix + "/evaluateELOnExecution");
     }
     
     public ValidatorMeta()
@@ -128,6 +135,8 @@
                     other._tagSuperclass);            
         }
 
+        _tagHandler = ModelUtils.merge(this._tagHandler, other._tagHandler);
+        _evaluateELOnExecution = ModelUtils.merge(this._evaluateELOnExecution, other._evaluateELOnExecution);
         
         _validatorId = ModelUtils.merge(this._validatorId, other._validatorId);
 
@@ -243,6 +252,28 @@
         return _tagSuperclass;
     }
     
+    /**
+     * Specifies the class of the Facelets tag handler (component handler) for
+     * this component.
+     * <p>
+     * Note that a Facelets tag handler class is not needed for most components.
+     * 
+     * @since 1.0.8
+     */
+    public void setTagHandler(String tagHandler)
+    {
+        _tagHandler = tagHandler;
+    }
+
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public String getTagHandler()
+    {
+        return _tagHandler;
+    }
+    
     public void setSerialuidtag(String serialuidtag)
     {
         _serialuidtag = serialuidtag;
@@ -283,6 +314,24 @@
         return ModelUtils.defaultOf(_configExcluded,false);
     }    
 
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public void setEvaluateELOnExecution(Boolean evaluateELOnExecution)
+    {
+        this._evaluateELOnExecution = evaluateELOnExecution;
+    }
+
+    /**
+     * 
+     * @since 1.0.8
+     */
+    public Boolean isEvaluateELOnExecution()
+    {
+        return ModelUtils.defaultOf(_evaluateELOnExecution,false);
+    }
+
     //THIS METHODS ARE USED FOR VELOCITY TO GET DATA AND GENERATE CLASSES
 
     // A transient attribute that is computed on-demand from the model data
diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java
index b5f5ea2..0f4d579 100644
--- a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java
@@ -281,9 +281,14 @@
                 continue;
             }
             QdoxHelper.initConverterAncestry(processedClasses, model, converter);
-            // TODO: why is there no check for Converter class existence here??
-            // ANS: there is no automatic generation of converter class.
-            
+
+            //Check if the converter class file exists
+            if (!IOUtils.existsSourceFile(StringUtils.replace(
+                    converter.getClassName(),".","/")+".java", sourceDirs))
+            {
+                converter.setGeneratedComponentClass(Boolean.TRUE);
+            }
+
             // Check if the tag class java file exists in the source dirs
             if (QdoxHelper.isTagClassMissing(converter.getTagClass(), sourceDirs))
             {
@@ -686,8 +691,10 @@
         String bodyContent = QdoxHelper.getString(clazz, "bodyContent", props, null);
         String tagClass = QdoxHelper.getString(clazz, "tagClass", props, null);
         String tagSuperclass = QdoxHelper.getString(clazz, "tagSuperclass", props, null);
+        String tagHandler = QdoxHelper.getString(clazz, "tagHandler", props, null);
         String serialuidtag = QdoxHelper.getString(clazz, "serialuidtag", props, null);
         Boolean configExcluded = QdoxHelper.getBoolean(clazz,"configExcluded",props,null);   
+        Boolean evaluateELOnExecution = QdoxHelper.getBoolean(clazz,"evaluateELOnExecution",props,null);
 
         ConverterMeta converter = new ConverterMeta();
         initClassMeta(model, clazz, converter, classNameOverride);
@@ -695,11 +702,13 @@
         converter.setBodyContent(bodyContent);
         converter.setTagClass(tagClass);
         converter.setTagSuperclass(tagSuperclass);
+        converter.setTagHandler(tagHandler);
         converter.setConverterId(converterId);
         converter.setDescription(shortDescription);
         converter.setLongDescription(longDescription);
         converter.setSerialuidtag(serialuidtag);
         converter.setConfigExcluded(configExcluded);
+        converter.setEvaluateELOnExecution(evaluateELOnExecution);
         
         // Now here walk the component looking for property annotations.
         processComponentProperties(clazz, converter);
@@ -782,8 +791,10 @@
         String bodyContent = QdoxHelper.getString(clazz, "bodyContent", props, null);
         String tagClass = QdoxHelper.getString(clazz, "tagClass", props, null);        
         String tagSuperclass = QdoxHelper.getString(clazz, "tagSuperclass", props, null);
+        String tagHandler = QdoxHelper.getString(clazz, "tagHandler", props, null);
         String serialuidtag = QdoxHelper.getString(clazz, "serialuidtag", props, null);
-        Boolean configExcluded = QdoxHelper.getBoolean(clazz,"configExcluded",props,null);   
+        Boolean configExcluded = QdoxHelper.getBoolean(clazz,"configExcluded",props,null);
+        Boolean evaluateELOnExecution = QdoxHelper.getBoolean(clazz,"evaluateELOnExecution",props,null);
         
         ValidatorMeta validator = new ValidatorMeta();
         initClassMeta(model, clazz, validator, classNameOverride);
@@ -791,11 +802,13 @@
         validator.setBodyContent(bodyContent);
         validator.setTagClass(tagClass);
         validator.setTagSuperclass(tagSuperclass);
+        validator.setTagHandler(tagHandler);
         validator.setValidatorId(validatorId);
         validator.setDescription(shortDescription);
         validator.setLongDescription(longDescription);
         validator.setSerialuidtag(serialuidtag);
         validator.setConfigExcluded(configExcluded);
+        validator.setEvaluateELOnExecution(evaluateELOnExecution);
         
         // Now here walk the component looking for property annotations.
         processComponentProperties(clazz, validator);
diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java
index f209213..0be52a4 100644
--- a/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java
@@ -272,6 +272,13 @@
 
                 if (converter.getModelId().equals(model.getModelId()))
                 {
+                    if (converter.isGeneratedComponentClass().booleanValue())
+                    {
+                        getLog().info("Adding Generated: "+ converter.getClassName());
+                        exclusions.add(StringUtils.replace(
+                                converter.getClassName(), ".", "/")
+                                + ".java");
+                    }
                     if (converter.isGeneratedTagClass().booleanValue())
                     {
                         getLog().info("Adding Generated: "+ converter.getTagClass());
diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/converterClassMacros11.vm b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/converterClassMacros11.vm
new file mode 100644
index 0000000..8362de7
--- /dev/null
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/converterClassMacros11.vm
@@ -0,0 +1,4 @@
+## Macro definitions for component class definition

+##

+## Velocity macros defined in this file will be available when executing

+## the componentClass11.vm template file.
\ No newline at end of file
diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config11.vm b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config11.vm
index f688b2e..22d5731 100644
--- a/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config11.vm
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config11.vm
@@ -40,7 +40,9 @@
 #end
 #set ($converterList = ${model.getConverters()})
 #foreach( $converter in $converterList )
-#if ($modelIds.contains($converter.modelId))
+#if ($modelIds.contains($converter.modelId) &&
+    !($converter.isConfigExcluded().booleanValue()) &&
+    $converter.converterId)
   <converter>
     <converter-id>$converter.converterId</converter-id>
     <converter-class>$converter.className</converter-class>
diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config12.vm b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config12.vm
index 21630ca..2d5c7e7 100644
--- a/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config12.vm
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/faces-config12.vm
@@ -39,7 +39,9 @@
 #end

 #set ($converterList = ${model.getConverters()})

 #foreach( $converter in $converterList )

-#if ($modelIds.contains($converter.modelId))

+#if ($modelIds.contains($converter.modelId) &&

+    !($converter.isConfigExcluded().booleanValue()) &&

+    $converter.converterId)

   <converter>

     <converter-id>$converter.converterId</converter-id>

     <converter-class>$converter.className</converter-class>

diff --git a/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/tomahawk.vm b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/tomahawk.vm
new file mode 100644
index 0000000..c2b9e84
--- /dev/null
+++ b/maven2-plugins/myfaces-builder-plugin/src/main/resources/META-INF/tomahawk.vm
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>

+<!--

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+-->

+<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

+<taglib>

+   <tlib-version>1.0</tlib-version>

+   <jsp-version>1.2</jsp-version>

+   <short-name>$shortname</short-name>

+   <uri>$uri</uri>

+   <display-name>$displayname</display-name>

+   <description>$description</description>

+

+$baseContent

+

+    <!-- Component Tags -->

+#set ($componentList = ${model.getComponents()})

+#foreach( $component in $componentList )

+#if ($modelIds.contains($component.modelId) 

+    && ($component.name))

+#if ($utils.getTagPrefix($component.name) == $shortname) 

+   <tag>

+      <name>$utils.getTagName($component.name)</name>

+      <tag-class>$component.tagClass</tag-class>

+#if ($component.bodyContent)

+      <body-content>$component.bodyContent</body-content>

+#else

+      <body-content>JSP</body-content>

+#end

+      <description><![CDATA[$component.longDescription]]></description>

+      

+#set ($propertyList = ${component.propertyList})

+#foreach( $property in $propertyList )

+#if (!$property.isTagExcluded())

+      <attribute>

+         <name>$property.jspName</name>

+         <required>$property.isRequired()</required>

+         <rtexprvalue>false</rtexprvalue>

+         <type>java.lang.String</type>

+#if ($property.longDescription)

+         <description><![CDATA[$property.longDescription]]></description>

+#else

+         <description><![CDATA[]]></description>

+#end

+      </attribute>

+#end

+#end

+   </tag>

+#end

+#end

+#end

+   <!-- Converter tags -->

+#set ($componentList = ${model.getConverters()})

+#foreach( $component in $componentList )

+#if ($modelIds.contains($component.modelId) 

+    && ($component.name))

+#if ($utils.getTagPrefix($component.name) == $shortname) 

+   <tag>

+      <name>$utils.getTagName($component.name)</name>

+      <tag-class>$component.tagClass</tag-class>

+#if ($component.bodyContent)

+      <body-content>$component.bodyContent</body-content>

+#else

+      <body-content>empty</body-content>

+#end

+      <description><![CDATA[$component.longDescription]]></description>

+      

+#set ($propertyList = ${component.propertyList})

+#foreach( $property in $propertyList )

+#if (!$property.isTagExcluded())

+      <attribute>

+         <name>$property.name</name>

+         <required>$property.isRequired()</required>

+         <rtexprvalue>false</rtexprvalue>

+         <type>java.lang.String</type>

+#if ($property.longDescription)

+         <description><![CDATA[$property.longDescription]]></description>

+#else

+         <description><![CDATA[]]></description>

+#end

+      </attribute>

+#end

+#end

+   </tag>

+#end

+#end

+#end

+   <!-- Validator tags -->

+#set ($componentList = ${model.getValidators()})

+#foreach( $component in $componentList )

+#if ($modelIds.contains($component.modelId) 

+    && ($component.name))

+#if ($utils.getTagPrefix($component.name) == $shortname) 

+   <tag>

+      <name>$utils.getTagName($component.name)</name>

+      <tag-class>$component.tagClass</tag-class>

+#if ($component.bodyContent)

+      <body-content>$component.bodyContent</body-content>

+#else

+      <body-content>empty</body-content>

+#end

+      <description><![CDATA[$component.longDescription]]></description>

+      

+#set ($propertyList = ${component.propertyList})

+#foreach( $property in $propertyList )

+#if (!$property.isTagExcluded())

+      <attribute>

+         <name>$property.name</name>

+         <required>$property.isRequired()</required>

+         <rtexprvalue>false</rtexprvalue>

+         <type>java.lang.String</type>

+#if ($property.longDescription)

+         <description><![CDATA[$property.longDescription]]></description>

+#else

+         <description><![CDATA[]]></description>

+#end

+      </attribute>

+#end

+#end

+   </tag>

+#end

+#end

+#end

+   <!-- Single Tags -->

+#set ($tagList = $model.getTags())

+#foreach( $tag in $tagList )

+#if ($modelIds.contains($tag.modelId))

+   <tag>

+      <name>$utils.getTagName($tag.name)</name>

+      <tag-class>$tag.className</tag-class>

+      <body-content>$tag.bodyContent</body-content>

+      <description><![CDATA[$tag.longDescription]]></description>

+#set ($attributeList = ${tag.attributeList})

+#foreach( $attribute in $attributeList )

+      <attribute>

+         <name>$attribute.name</name>

+         <required>$attribute.isRequired()</required>

+         <rtexprvalue>$attribute.isRtexprvalue()</rtexprvalue>

+#if ($attribute.className)         

+         <type>$attribute.className</type>

+#else

+         <type>java.lang.String</type>

+#end

+#if ($property.longDescription)

+         <description><![CDATA[$property.longDescription]]></description>

+#else

+         <description><![CDATA[]]></description>

+#end

+      </attribute>

+#end

+   </tag>

+#end

+#end

+</taglib>
\ No newline at end of file