[maven-release-plugin]  copy for tag lu4242_m2_plugins_102_release/myfaces-builder-plugin
diff --git a/myfaces-builder-plugin/LICENSE.txt b/myfaces-builder-plugin/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/myfaces-builder-plugin/LICENSE.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
diff --git a/myfaces-builder-plugin/NOTICE.txt b/myfaces-builder-plugin/NOTICE.txt
new file mode 100644
index 0000000..fa3dbd6
--- /dev/null
+++ b/myfaces-builder-plugin/NOTICE.txt
@@ -0,0 +1,16 @@
+=========================================================================
+==  NOTICE file corresponding to section 4(d) of the Apache License,   ==
+==  Version 2.0, in this case for the Apache MyFaces Maven Plugins     ==
+=========================================================================
+
+This product includes software developed by 
+The Apache Software Foundation (http://www.apache.org/).
+
+Portions of this software were originally based on the following:
+
+ - software copyright (c) 2000-2006, Oracle Corp, <http://www.oracle.com/>.
+and are licensed to the Apache Software Foundation under the 
+"Software Grant and Corporate Contribution License Agreement"
+
+See the LICENSE.txt file for information on all licenses 
+associated with this software.
diff --git a/myfaces-builder-plugin/pom.xml b/myfaces-builder-plugin/pom.xml
new file mode 100644
index 0000000..c488b8f
--- /dev/null
+++ b/myfaces-builder-plugin/pom.xml
@@ -0,0 +1,179 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.myfaces.buildtools</groupId>
+    <artifactId>myfaces-plugin-parent</artifactId>
+    <version>1.0.2</version>
+  </parent>
+
+  <groupId>org.apache.myfaces.buildtools</groupId>
+  <artifactId>myfaces-builder-plugin</artifactId> 
+  <version>1.0.2</version>
+  <packaging>maven-plugin</packaging>
+  <name>Apache MyFaces Buildtools Maven2 Builder Plugin</name>
+  <description>
+    A maven plugin that uses annotations (java15 or doclet style) to generate the necessary JSF configuration
+    files (.tld, faces-config.xml, etc) and optionally Tag, Validator and Component classes.
+  </description>
+
+  <build>
+    <plugins>
+      <!-- required for plexus, but we are not using this right now
+      <plugin>
+        <artifactId>maven-plugin-plugin</artifactId>
+        <configuration>
+          <goalPrefix>myfaces-builder</goalPrefix>
+        </configuration>
+      </plugin>
+       -->
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.0.2</version>
+        <inherited>true</inherited>
+        <configuration>
+          <source>1.4</source>
+          <target>1.4</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.4.2</version>
+      </plugin>
+    </plugins>
+  </build>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-plugin-plugin</artifactId>
+        <version>2.2</version>
+      </plugin>
+    </plugins>
+  </reporting>
+  
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0</version>
+    </dependency>
+    
+    <dependency>    
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-dependency-plugin</artifactId>
+      <version>2.0</version>
+    </dependency>   
+
+    <dependency>
+      <groupId>com.thoughtworks.qdox</groupId>
+      <artifactId>qdox</artifactId>
+      <version>1.6.3</version>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-digester</groupId>
+      <artifactId>commons-digester</artifactId>
+      <version>1.8</version>
+    </dependency>
+
+    <!--
+    <dependency>
+    	<groupId>xml-apis</groupId>
+    	<artifactId>xml-apis</artifactId>
+    	<version>1.0.b2</version>
+    	<scope>runtime</scope>
+    </dependency>
+    -->
+
+    <dependency>
+      <groupId>saxon</groupId>
+      <artifactId>saxon</artifactId>
+      <version>6.5.3</version>
+      <scope>runtime</scope>
+    </dependency>
+    
+    <!--
+    <dependency>
+      <groupId>xerces</groupId>
+      <artifactId>xercesImpl</artifactId>
+      <version>2.6.2</version>
+      <scope>runtime</scope>
+    </dependency>
+    -->
+
+    <dependency>
+    	<groupId>stax</groupId>
+    	<artifactId>stax-api</artifactId>
+    	<version>1.0.1</version>
+    	<!-- <scope>compile</scope>  -->
+    </dependency>
+
+    <dependency>
+    	<groupId>stax</groupId>
+    	<artifactId>stax</artifactId>
+    	<version>1.2.0</version>
+    	<!-- <scope>runtime</scope>  -->
+    </dependency>
+
+    <dependency>
+      <groupId>velocity</groupId>
+      <artifactId>velocity</artifactId>
+      <version>1.5</version>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+      <version>3.1</version>
+    </dependency>
+    <!--     
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-velocity</artifactId>
+      <version>1.1.7</version>
+    </dependency>
+     -->
+    
+    <!-- Reporting required API-->   
+    <dependency>
+      <groupId>org.apache.maven.reporting</groupId>
+      <artifactId>maven-reporting-impl</artifactId>
+      <version>2.0</version>
+    </dependency>
+        
+    <dependency>
+      <groupId>org.apache.maven.doxia</groupId>
+      <artifactId>doxia-core</artifactId>
+      <version>1.0-alpha-7</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.maven.doxia</groupId>
+      <artifactId>doxia-site-renderer</artifactId>
+      <version>1.0-alpha-7</version>
+    </dependency>
+    <!-- End Reporting required API -->
+
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.13</version>
+    </dependency>
+  </dependencies>
+
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/myfaces/myfaces-build-tools/tags/lu4242_m2_plugins_102_release/myfaces-builder-plugin</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/myfaces/myfaces-build-tools/branches/lu4242_m2_plugins_102_release/myfaces-builder-plugin</developerConnection>
+    <url>http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/tags/lu4242_m2_plugins_102_release/myfaces-builder-plugin</url>
+  </scm>
+</project>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java
new file mode 100644
index 0000000..39ac9f5
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java
@@ -0,0 +1,486 @@
+/*
+ *  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.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.model.Resource;
+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.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.qdox.QdoxModelBuilder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.BuildException;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Maven goal which runs one or more ModelBuilder objects to gather metadata
+ * about JSF artifacts into a Model object, then save that model object as an
+ * xml file for use by other goals of this plugin.
+ * <p>
+ * By default, the generated file is named "META-INF/myfaces-metadata.xml".
+ * This file will be included in the final artifact for this project. Having
+ * that metadata file embedded in the generated jarfile is useful for two
+ * purposes:
+ * <ul>
+ * <li>It is needed if other projects then use the maven-builder-plugin to
+ * create subclasses of the jsf classes in this project.</li>
+ * <li>It is good documentation (more precise than the tld and faces-config.xml
+ * files).</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Note that the generated file contains all the metadata needed by this
+ * project, including a copy of all the metadata from other projects that
+ * this one depends on. All other goals of this plugin can execute with
+ * just the generated metadata as input, without needing to load other
+ * projects. Each entry in the metadata is labelled with a "modelId"
+ * property that indicates where it originally came from.
+ * </p>
+ * 
+ * @requiresDependencyResolution compile
+ * @goal build-metadata
+ * @phase generate-sources
+ */
+public class BuildMetaDataMojo extends AbstractMojo
+{
+    /**
+     * Injected Maven project object.
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * Build directory for all generated stuff.
+     * <p>
+     * This mojo registers the specified directory with Maven as a resource dir. The
+     * maven-resources-plugin will then read the files from this dir and copy them
+     * into the "central" target directory from which the jarfile is built. 
+     * </p>
+     * 
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+     */
+    private File targetDirectory;
+
+    /**
+     * Name of the metadata file to generate, relative to targetDirectory.
+     * 
+     * @parameter
+     */
+    private String outputFile = "META-INF/myfaces-metadata.xml";
+
+    /**
+     * The modelId to associate with all model items discovered in the
+     * source directories of this project.
+     * <p>
+     * This value <i>must</i> be unique for each project. If not specified,
+     * then it defaults to the artifactId of the current maven project.
+     * </p>
+     * <p>
+     * In later phases, goals are passed the complete metadata model which
+     * mixes items discovered here with items imported from metadata in 
+     * other projects. The modelId is used to figure out which of the
+     * items should be processed (ie which ones are associated with this
+     * project) and which should be ignored.
+     * </p>
+     *
+     * @parameter expression="${project.artifactId}"
+     */
+    private String modelId;
+    
+    /**
+     * Replace the package prefix.
+     * <p>
+     * This allows a project that inherits metadata from some other project to force
+     * copies of the Tag classes to be created in a namespace of its own choosing.
+     * </p>
+     * <p>
+     * This is used in particular to create copies of the Tag classes in myfaces-impl
+     * within other projects so that they can be used as base classes for other tags
+     * within that project. The original tag present in the myfaces-impl.jar cannot
+     * be used as a base because that would prevent the derived project from running
+     * with other JSF implementations.
+     * </p>
+     * <p>
+     * The child project first defines this (and replacePackagePrefixTagTo); as the
+     * inherited metadata is merged the tagClass attribute is modified. Then during
+     * the tag class generation goal, the modelId of the inherited project is included
+     * in the list of modelIds to process. That causes the tag classes to be generated
+     * again - but this time in a different package.
+     * </p>
+     * 
+     * @parameter
+     */
+    private String replacePackagePrefixTagFrom;
+
+    /**
+     * Replace the package prefix
+     * <p>
+     * See replacePackagePrefixTagTo.
+     * </p>
+     * 
+     * @parameter
+     */
+    private String replacePackagePrefixTagTo;
+    
+    /**
+     * Specify the order in which models are to be merged (not usually needed).
+     * <p>
+     * When two different models define exactly the same item (ie the "class" attribute
+     * for two items is the same) then the one from the model that is merged first is
+     * used, and the later one is ignored.
+     * </p>
+     * <p>
+     * This property allows the order of merging to be controlled; models are merged in
+     * the order specified in this list. Any models whose ids are not in this list are
+     * then merged in an undefined order at the end.
+     * </p>
+     * <p>
+     * Setting this property is not normally necessary; typically models inherited from
+     * dependencies define different model items (ie have no overlap). However consider
+     * the situation where project A defines a model, project B extends A, then project C
+     * extends B. In this case, both A and B are in the dependencies, but the metadata in
+     * project B contains a complete copy of all the data from A. However B's metadata is
+     * from <i>the version of A that it was compiled against</i> which might not be the
+     * version of A that is in the dependencies. For safety in this case, it is better to
+     * ensure that project B's metadata is loaded first; this can possibly hide any new
+     * features (or bugfixes) from the new release of A, but also ensures that classes
+     * in C which extend classes in B do not declare features that B does not support.
+     * </p>
+     * <p>
+     * This property is only needed in rare situations; normally it can be omitted.
+     * </p>
+     * 
+     * @parameter
+     */
+    private List orderModelIds;
+    
+    /**
+     * An optional list of models to import from dependency jars.
+     * <p>
+     * The default behaviour is to scan all jar dependencies for metadata files, and
+     * merge all the data into the model for this project. If this property is set,
+     * then metadata found in dependencies is only merged if the modelId matches one
+     * in this list.
+     * </p>
+     * <p>
+     * Note that by default, a project's modelId is the same as the artifactId.
+     * </p>
+     * 
+     * @parameter
+     */
+    private List dependencyModelIds;
+    
+    /**
+     * The name of a metadata file to merge into the model for the current project.
+     * <p>
+     * This file is always loaded first, before any metadata from dependencies is
+     * loaded, and before scanning of the source directories for the current
+     * project is done.
+     * </p>
+     * <p>
+     * The specified filename is relative to the current working directory.
+     * </p>
+     * <p>
+     * Normally, this option is not used and any models that this project extends
+     * are simply automatically detected via scanning of the maven dependencies and
+     * loaded from the dependency jarfile. However there are a couple of situations
+     * where it is useful to specify an explicit metadata file to load instead.  
+     * </p>
+     * <p> 
+     * One example is when a project extends components in a project which was not
+     * built with the myfaces-builder-plugin (or where myfaces-builder-plugin
+     * support is only in a not-yet-released version). In this case, a metadata file
+     * can be created by hand (or generated from the unreleased trunk version) and
+     * explicitly loaded via this property.
+     * </p>
+     * <p>
+     * A second example is when it is necessary to add some custom model definitions to
+     * the model to be built, eg to override buggy or missing metadata in a project
+     * that this project extends. Of course this is hopefully not needed; it would be
+     * better to get a bugfix release of the parent project out instead!
+     * </p>
+     * 
+     * @parameter
+     */
+    private File inputFile;
+    
+    /**
+     * A comma separated list of file patterns to include when building the
+     * model.  i.e.  **\/*.java
+     * 
+     * @parameter
+     */
+    private String includes;
+    
+    /**
+     *  A comma separated list of file patterns to exclude when building the
+     *  model.  i.e.  **\/*.java
+     * @parameter
+     */
+    private String excludes;
+    
+    /**
+     * Create a metadata file containing information imported from other projects
+     * plus data extracted from annotated classes in this project.
+     */
+    public void execute() throws MojoExecutionException
+    {
+        try
+        {
+            // Tell Maven to add this directory to its "resources" path. 
+            // The maven-resources-plugin will then copy all the files
+            // from this directory to its own target directory, which is
+            // where the final jar artifact is built from.
+            addResourceRoot(project, targetDirectory.getCanonicalPath());
+        }
+        catch(IOException e)
+        {
+            throw new MojoExecutionException("Error during generation", e);
+        }
+        
+        List models = IOUtils.getModelsFromArtifacts(project); 
+        models = sortModels(models);
+
+        Model model = new Model();
+
+        if (inputFile != null)
+        {
+            // An explicitly-specified input model takes precedence
+            Model fileModel = IOUtils.loadModel(inputFile);
+            model.merge(fileModel);
+        }
+        
+        
+        for (Iterator it = models.iterator(); it.hasNext();)
+        {
+            Model artifactModel = (Model) it.next();
+            
+            if ((dependencyModelIds == null) || dependencyModelIds.contains(artifactModel.getModelId()))
+            {
+                model.merge(artifactModel);
+            }
+        }
+
+        buildModel(model, project);
+        resolveReplacePackage(model);
+        
+        IOUtils.saveModel(model, new File(targetDirectory, outputFile));
+        
+        validateComponents(model);
+    }
+    
+    /**
+     * Order the models as specified by the modelIdOrder property.
+     * <p>
+     * Tomahawk sandbox depends from myfaces-api and tomahawk core, so
+     * the myfaces-metadata.xml of tomahawk core must be merged first
+     * and then myfaces-api.
+     * <p>
+     * In some cases, the same metadata can be imported multiple times.
+     * For example, Project A has metadata. Project B extends A, and
+     * Project C extends B. 
+     * 
+     * @param models
+     * @return
+     */
+    private List sortModels(List models)
+    {
+        if (orderModelIds == null)
+        {
+            //No changes
+            return models;
+        }
+        
+        Map modelsMap = new HashMap();
+        List modelsSorted = new ArrayList();
+
+        // First, put all models into a map keyed by modelId.
+        for (Iterator it = models.iterator(); it.hasNext();)
+        {
+            Model artifactModel = (Model) it.next();
+            modelsMap.put(artifactModel.getModelId(), artifactModel);
+        }
+
+        // now pull them out of the map in the order specified by orderModelIds.
+        for (Iterator it = orderModelIds.iterator(); it.hasNext();)
+        {
+            String modelId = (String) it.next();
+            
+            Model artifactModel = (Model) modelsMap.get(modelId);
+            if (artifactModel != null)
+            {
+                modelsMap.remove(modelId);
+                modelsSorted.add(artifactModel);
+            }
+        }
+
+        // and any of the ones that remain in the map (ie had no order specified)
+        // now get added to the end of the list.
+        modelsSorted.addAll(modelsMap.values());
+        
+        return modelsSorted;
+    }
+    
+    private void resolveReplacePackage(Model model)
+    {
+        if (replacePackagePrefixTagFrom == null ||
+                replacePackagePrefixTagTo == null)
+        {
+            return;
+        }
+        
+        List components = model.getComponents();
+        for (Iterator i = components.iterator(); i.hasNext();)
+        {
+            ComponentMeta comp = (ComponentMeta) i.next();
+            
+            if (comp.getTagClass() == null)
+            {
+                continue;
+            }
+            if (comp.getTagClass().startsWith(replacePackagePrefixTagFrom))
+            {
+                comp.setTagClass(StringUtils.replaceOnce(
+                        comp.getTagClass(), replacePackagePrefixTagFrom, replacePackagePrefixTagTo));
+            }
+        }
+    }
+    
+
+    /**
+     * Execute ModelBuilder classes to create the Model data-structure.
+     */
+    private Model buildModel(Model model, MavenProject project)
+            throws MojoExecutionException
+    {
+        try
+        {
+            QdoxModelBuilder builder = new QdoxModelBuilder();
+            model.setModelId(modelId);
+            builder.buildModel(model, project,includes,excludes);            
+            return model;
+        }
+        catch (BuildException e)
+        {
+            throw new MojoExecutionException("Unable to build metadata", e);
+        }
+    }
+    
+    protected void addResourceRoot(MavenProject project, String resourceRoot)
+    {
+        List resources = project.getBuild().getResources();
+        Resource resource = new Resource();
+        resource.setDirectory(resourceRoot);
+        resources.add(resource);
+    }
+    
+    /**
+     * Check that each component is valid (has all mandatory properties etc).
+     * <p>
+     * Most sanity checks are best done after the myfaces-metadata.xml file
+     * is created, so that if an error occurs the file is available for the
+     * user to inspect. In particular, problems due to missing properties
+     * which are permitted to be inherited can be tricky to track down if
+     * the metadata file is not available.
+     * <p>
+     * TODO: make this gather up all the errors, then report them at once
+     * rather than stopping on the first error found.
+     */
+    private void validateComponents(Model model) throws MojoExecutionException
+    {
+        for(Iterator i = model.components(); i.hasNext(); )
+        {
+            ComponentMeta component = (ComponentMeta) i.next();
+            validateComponent(model, component);
+        }
+    }
+    
+    private void validateComponent(Model model, ComponentMeta component)
+    throws MojoExecutionException
+    {
+        if (component.getName() != null)
+        {
+            if (component.getDescription() == null)
+            {
+                throw new MojoExecutionException(
+                        "Missing mandatory property on component " + component.getClassName()
+                        + " [sourceClass=" + component.getSourceClassName() + "]: description");
+            }
+
+            if (component.getType() == null)
+            {
+                throw new MojoExecutionException(
+                        "Missing mandatory property on component " + component.getClassName()
+                        + " [sourceClass=" + component.getSourceClassName() + "]: type");
+            }
+            
+            // this is a concrete component, so it must have a family property
+            validateComponentFamily(model, component);
+        }
+    }
+    
+    private void validateComponentFamily(Model model, ComponentMeta component)
+    throws MojoExecutionException
+    {
+        // TODO: clean this code up, it is pretty ugly
+        boolean familyDefined = false;
+        ComponentMeta curr = component;
+        while ((curr != null) && !familyDefined)
+        {
+            if (curr.getFamily() != null)
+            {
+                familyDefined = true;
+            }
+            else
+            {
+                String parentName = curr.getParentClassName();
+                if (parentName == null)
+                {
+                    curr = null;
+                }
+                else
+                {
+                    curr = model.findComponentByClassName(parentName);
+                    if (curr == null)
+                    {
+                        throw new MojoExecutionException(
+                                "Parent class not found for component " + component.getClassName()
+                                + " [sourceClass=" + component.getSourceClassName() + "]");
+                    }
+                }
+            }
+        }
+        if (!familyDefined)
+        {
+            throw new MojoExecutionException(
+                "Missing mandatory property on component " + component.getClassName()
+                + " [sourceClass=" + component.getSourceClassName() + "]: family");
+        }
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/Flattener.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/Flattener.java
new file mode 100644
index 0000000..54658c1
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/Flattener.java
@@ -0,0 +1,194 @@
+/*
+ *  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.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
+
+/**
+ */
+public class Flattener
+{
+    private final Log log = LogFactory.getLog(Flattener.class);
+
+    private Model model;
+    private Set flattened = new HashSet();
+
+    public Flattener(Model model)
+    {
+        this.model = model;
+    }
+
+    /**
+     * Flatten the specified model.
+     * <p>
+     * In the flattened representation, each model object directly contains the
+     * data that it inherits from its parents, so that the getter methods return
+     * all available metadata, not just the data that was defined directly on
+     * that item.
+     */
+    public void flatten()
+    {
+        flattenComponentProperties();
+        flattenValidatorProperties();
+        flattenConverterProperties();
+    }
+
+    private void flattenComponentProperties()
+    {
+        List components = model.getComponents();
+        for (Iterator i = components.iterator(); i.hasNext();)
+        {
+            ComponentMeta comp = (ComponentMeta) i.next();
+            flattenComponent(comp);
+        }
+    }
+
+    private void flattenComponent(ComponentMeta component)
+    {
+        if (flattened.contains(component))
+        {
+            // already done
+            return;
+        }
+        String parentClassName = component.getParentClassName();
+        if (parentClassName != null)
+        {
+            ComponentMeta parent = model
+                    .findComponentByClassName(parentClassName);
+            if (parent != null)
+            {
+                flattenComponent(parent);
+                component.merge(parent);
+            }
+            else
+            {
+                //How to manage a component that its
+                //parent class is not a real component?
+                //Use UIComponent instead and log a warn
+                //so if needed we can fix this.
+                log.warn("Component:"+component.getClassName()+
+                        " without a parent defined as component, using " +
+                        "UIComponent");
+                parent = model
+                    .findComponentByClassName("javax.faces.component.UIComponent");
+                flattenComponent(parent);
+                component.merge(parent);                
+            }
+        }
+
+        List interfaceClassNames = component.getInterfaceClassNames();
+        for (Iterator i = interfaceClassNames.iterator(); i.hasNext();)
+        {
+            String ifaceClassName = (String) i.next();
+            ComponentMeta iface = model
+                    .findComponentByClassName(ifaceClassName);
+            flattenComponent(iface);
+            component.merge(iface);
+        }
+
+        flattened.add(component);
+    }
+    
+    private void flattenValidatorProperties()
+    {
+        List validator = model.getValidators();
+        for (Iterator i = validator.iterator(); i.hasNext();)
+        {
+            ValidatorMeta val = (ValidatorMeta) i.next();
+            flattenValidator(val);
+        }
+    }
+    
+    private void flattenValidator(ValidatorMeta validator)
+    {
+        if (flattened.contains(validator))
+        {
+            // already done
+            return;
+        }
+        String parentClassName = validator.getParentClassName();
+        if (parentClassName != null)
+        {
+            ValidatorMeta parent = model
+                    .findValidatorByClassName(parentClassName);
+            if (parent != null)
+            {
+                flattenValidator(parent);
+                validator.merge(parent);
+            }
+            else
+            {
+                //How to manage a validator that its
+                //parent class is not a real validator?
+                //Ans: no problem, do nothing.
+            }
+        }
+
+        flattened.add(validator);
+    }
+
+    private void flattenConverterProperties()
+    {
+        List converter = model.getConverters();
+        for (Iterator i = converter.iterator(); i.hasNext();)
+        {
+            ConverterMeta val = (ConverterMeta) i.next();
+            flattenConverter(val);
+        }
+    }
+    
+    private void flattenConverter(ConverterMeta converter)
+    {
+        if (flattened.contains(converter))
+        {
+            // already done
+            return;
+        }
+        String parentClassName = converter.getParentClassName();
+        if (parentClassName != null)
+        {
+            ConverterMeta parent = model
+                    .findConverterByClassName(parentClassName);
+            if (parent != null)
+            {
+                flattenConverter(parent);
+                converter.merge(parent);
+            }
+            else
+            {
+                //How to manage a validator that its
+                //parent class is not a real validator?
+                //Ans: no problem, do nothing.
+            }
+        }
+
+        flattened.add(converter);
+    }
+}
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java
new file mode 100644
index 0000000..9c6e31c
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java
@@ -0,0 +1,383 @@
+/*
+ *  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.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.commons.digester.Digester;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.xml.sax.SAXException;
+
+/**
+ * Utilities to write a Model as xml, and read a Model in from xml.
+ */
+public class IOUtils
+{
+    
+    private final static String MYFACES_METADATA = "META-INF/myfaces-metadata.xml";
+    
+    /**
+     * Write the contents of the model to an xml file.
+     */
+    public static void saveModel(Model model, File outfile)
+            throws MojoExecutionException
+    {
+        FileWriter writer = null;
+
+        try
+        {
+            outfile.getParentFile().mkdirs();
+
+            writer = new FileWriter(outfile);
+            writeModel(model, writer);
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Unable to save data", e);
+        }
+        finally
+        {
+            try
+            {
+                if (writer != null)
+                {
+                    writer.close();
+                }
+            }
+            catch (IOException e)
+            {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Write the contents of the model to a provided Writer object.
+     */
+    public static void writeModel(Model model, Writer writer)
+            throws MojoExecutionException
+    {
+        try
+        {
+            writer.write("<?xml version='1.0' ?>\n");
+            PrintWriter pw = new PrintWriter(writer);
+            XmlWriter xmlWriter = new XmlWriter(pw);
+            Model.writeXml(xmlWriter, model);
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Unable to save data", e);
+        }
+    }
+
+    /**
+     * Read the contents of the model from an xml file.
+     */
+    public static Model loadModel(File infile) throws MojoExecutionException
+    {
+        FileReader reader = null;
+        try
+        {
+            reader = new FileReader(infile);
+            return readModel(reader);
+        }
+        catch (FileNotFoundException e)
+        {
+            throw new MojoExecutionException("No metadata file:" + infile);
+        }
+        finally
+        {
+            if (reader != null)
+            {
+                try
+                {
+                    reader.close();
+                }
+                catch (IOException e)
+                {
+                    // ignore
+                }
+            }
+        }
+    }
+    
+    public static boolean existsSourceFile(String filename, List sourceDirs)
+    {
+        boolean existsFile = false;            
+        for (int i = 0; i < sourceDirs.size(); i++)
+        {
+            String srcDir = (String) sourceDirs.get(i);
+            
+            //This directory that contains target/myfaces-builder-plugin/main
+            //is banned, all here is generated
+            //so we don't take a look at this directory
+            if (srcDir.matches(".*\\W+target\\W+myfaces-builder-plugin\\W+main\\W+.*"))
+            {
+                continue;
+            }                        
+            
+            File f = new File(srcDir,filename);
+            if (f.exists())
+            {
+                existsFile=true;
+                break;
+            }
+        }
+        return existsFile;
+    }
+    
+    public static Model getModelFromArtifact(Artifact artifact) 
+        throws MojoExecutionException
+    {
+        Model model = null;
+        File jarFile = artifact.getFile();
+
+        URLClassLoader archetypeJarLoader;
+
+        InputStream is = null;
+        try
+        {
+            URL[] urls = new URL[1];
+            urls[0] = jarFile.toURI().toURL();
+            archetypeJarLoader = new URLClassLoader(urls);
+
+            is = getStream(MYFACES_METADATA, archetypeJarLoader);
+
+            if (is != null)
+            {
+                Reader r = null;
+                try
+                {
+                    r = new InputStreamReader(is);
+                    model = readModel(r);
+                    r.close();
+                }
+                catch (IOException e)
+                {
+                    throw new MojoExecutionException(
+                            "Error reading myfaces-metadata.xml form "
+                                    + artifact.getFile().getName(), e);
+                }
+                finally
+                {
+                    if (r != null)
+                    {
+                        try
+                        {
+                            r.close();
+                        }
+                        catch (IOException e)
+                        {
+                            //ignore
+                        }
+                    }
+                }
+
+                System.out.println("Artifact: "
+                        + artifact.getFile().getName()
+                        + " have META-INF/myfaces-metadata.xml");
+            }
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException(
+                    "Error reading myfaces-metadata.xml form "
+                            + artifact.getFile().getName(), e);
+        }
+        finally
+        {
+            if (is != null)
+            {
+                try
+                {
+                    is.close();
+                }
+                catch (IOException ex)
+                {
+                    //ignore
+                }
+            }
+        }
+
+        return model;
+    }
+
+    /**
+     * Scan every jarfile that this maven project has a dependency on, looking for metadata files.
+     * <p>
+     * Each file found is loaded into memory as a Model object and added to the list.
+     */
+    public static List getModelsFromArtifacts(MavenProject project)
+            throws MojoExecutionException
+    {
+        List models = new ArrayList();
+        
+        for (Iterator it = project.getArtifacts().iterator(); it.hasNext();)
+        {
+
+            Artifact artifact = (Artifact) it.next();
+            
+            if ("compile".equals(artifact.getScope())
+                    || "provided".equals(artifact.getScope())
+                    || "system".equals(artifact.getScope()))
+            {
+                //This is safe since we have all depencencies on the
+                //pom, so they are downloaded first by maven.
+                File jarFile = artifact.getFile();
+
+                URLClassLoader archetypeJarLoader;
+
+                InputStream is = null;
+                try
+                {
+                    URL[] urls = new URL[1];
+                    urls[0] = jarFile.toURL();
+                    archetypeJarLoader = new URLClassLoader(urls);
+
+                    is = getStream(MYFACES_METADATA, archetypeJarLoader);
+
+                    if (is != null)
+                    {
+                        Reader r = null;
+                        try
+                        {
+                            r = new InputStreamReader(is);
+                            Model m = readModel(r);
+                            models.add(m);
+                            r.close();
+                        }
+                        catch (IOException e)
+                        {
+                            throw new MojoExecutionException(
+                                    "Error reading myfaces-metadata.xml form "
+                                            + artifact.getFile().getName(), e);
+                        }
+                        finally
+                        {
+                            if (r != null)
+                            {
+                                try
+                                {
+                                    r.close();
+                                }
+                                catch (IOException e)
+                                {
+                                    //ignore
+                                }
+                            }
+                        }
+
+                        System.out.println("Artifact: "
+                                + artifact.getFile().getName()
+                                + " have META-INF/myfaces-metadata.xml");
+                    }
+                }
+                catch (IOException e)
+                {
+                    throw new MojoExecutionException(
+                            "Error reading myfaces-metadata.xml form "
+                                    + artifact.getFile().getName(), e);
+                }
+                finally
+                {
+                    if (is != null)
+                    {
+                        try
+                        {
+                            is.close();
+                        }
+                        catch (IOException ex)
+                        {
+                            //ignore
+                        }
+                    }
+                }
+            }
+        }
+        return models;
+    }
+        
+    private static InputStream getStream( String name,
+            ClassLoader loader )
+    {
+        if ( loader == null )
+        {
+            return Thread.currentThread().getContextClassLoader().getResourceAsStream( name );
+        }
+        return loader.getResourceAsStream( name );
+    }
+    
+    /**
+     * Read the contents of the model from a provided Reader object.
+     */
+    public static Model readModel(Reader reader) throws MojoExecutionException
+    {
+        try
+        {
+            //Digester d = new Digester();
+            SAXParserFactory spf = SAXParserFactory.newInstance();
+            spf.setNamespaceAware(true);
+            // requires JAXP 1.3, in JavaSE 5.0
+            // spf.setXIncludeAware(true);
+            Digester d = new Digester(spf.newSAXParser());
+            d.setNamespaceAware(true);            
+
+            Model.addXmlRules(d);
+
+            d.parse(reader);
+
+            Model model = (Model) d.getRoot();
+            return model;
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Unable to load metadata", e);
+        }
+        catch (SAXException e)
+        {
+            throw new MojoExecutionException("Unable to load metadata", e);
+        }
+        catch (ParserConfigurationException e)
+        {
+            // TODO Auto-generated catch block
+            throw new MojoExecutionException("Unable to load parser", e);
+        }
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeComponentsMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeComponentsMojo.java
new file mode 100644
index 0000000..ee73daa
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeComponentsMojo.java
@@ -0,0 +1,632 @@
+/*
+ *  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.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+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.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.BuildException;
+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;
+import com.thoughtworks.qdox.model.AbstractJavaEntity;
+import com.thoughtworks.qdox.model.Annotation;
+import com.thoughtworks.qdox.model.DocletTag;
+import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaField;
+import com.thoughtworks.qdox.model.JavaMethod;
+import com.thoughtworks.qdox.model.Type;
+
+/**
+ * Maven goal to generate java source code for Component classes.
+ * 
+ * @version $Id$
+ * @requiresDependencyResolution compile
+ * @goal make-components
+ * @phase generate-sources
+ */
+public class MakeComponentsMojo extends AbstractMojo
+{
+    final Logger log = Logger.getLogger(MakeComponentsMojo.class.getName());
+
+    /**
+     * Injected Maven project.
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @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";
+
+    /**
+     * @parameter expression="src/main/resources/META-INF"
+     */
+    private File templateSourceDirectory;
+
+    /**
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+     */
+    private File generatedSourceDirectory;
+
+    /**
+     * @parameter
+     */
+    private String packageContains;
+
+    /**
+     * @parameter
+     */
+    private String typePrefix;
+
+    /**
+     * @parameter
+     */
+    private boolean force;
+
+    /**
+     * @parameter
+     */
+    private boolean suppressListenerMethods;
+
+    /**
+     * @parameter
+     */
+    private String jsfVersion;
+    
+    /**
+     * @parameter
+     */
+    private List modelIds;
+
+    /**
+     * @parameter 
+     */
+    private String templateComponentName;
+    
+    /**
+     * 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();
+            generateComponents(model);
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Error generating components", e);
+        }
+        catch (BuildException e)
+        {
+            throw new MojoExecutionException("Error generating components", e);
+        }
+    }
+    
+    
+    private VelocityEngine initVelocity() throws MojoExecutionException
+    {
+
+        Properties p = new Properties();
+
+        p.setProperty( "resource.loader", "file, class" );
+        p.setProperty( "file.resource.loader.class",
+                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+        p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+        p.setProperty( "class.resource.loader.class",
+                "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+        p.setProperty( "class.resource.loader.path", "META-INF");            
+        p.setProperty( "velocimacro.library", "componentClassMacros11.vm");
+        p.setProperty( "velocimacro.permissions.allow.inline","true");
+        p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+        p.setProperty( "directive.foreach.counter.initial.value","0");
+        p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+        "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+        
+        File template = new File(templateSourceDirectory, _getTemplateName());
+        
+        if (template.exists())
+        {
+            log.info("Using template from file loader: "+template.getPath());
+        }
+        else
+        {
+            log.info("Using template from class loader: META-INF/"+_getTemplateName());
+        }
+                
+        VelocityEngine velocityEngine = new VelocityEngine();
+                
+        try
+        {
+            velocityEngine.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error creating VelocityEngine", e);
+        }
+        
+        return velocityEngine;
+    }
+    
+
+    /**
+     * Generates parsed components.
+     */
+    private void generateComponents(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.getComponents().iterator(); it.hasNext();)
+        {
+            ComponentMeta component = (ComponentMeta) it.next();
+            
+            if (component.getClassName() != null)
+            {
+                File f = new File(mainSourceDirectory, StringUtils.replace(
+                    component.getClassName(), ".", "/")+".java");
+                                
+                if (!f.exists() && canGenerateComponent(component))
+                {
+                    if (mainSourceDirectory2 != null)
+                    {
+                        File f2 = new File(mainSourceDirectory2, StringUtils.replace(
+                                component.getClassName(), ".", "/")+".java");
+                        if (f2.exists())
+                        {
+                            //Skip
+                            continue;
+                        }
+                    }
+                    log.info("Generating component class:"+component.getClassName());
+                    _generateComponent(velocityEngine, builder,component,baseContext);
+                }
+            }
+        }        
+    }
+    
+    public boolean canGenerateComponent(ComponentMeta component)
+    {
+        if ( modelIds.contains(component.getModelId())
+                && includePackage(component)
+                && includeType(component))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    public boolean includePackage(ComponentMeta component)
+    {
+        if (packageContains != null)
+        {
+            if (MyfacesUtils.getPackageFromFullClass(component.getClassName()).startsWith(packageContains))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+
+    public boolean includeType(ComponentMeta component)
+    {
+        if (typePrefix != null)
+        {
+            if (component.getType().startsWith(typePrefix))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+    
+    
+    /**
+     * Generates a parsed component.
+     * 
+     * @param component
+     *            the parsed component metadata
+     */
+    private void _generateComponent(VelocityEngine velocityEngine,
+            JavaDocBuilder builder,
+            ComponentMeta component, VelocityContext baseContext)
+            throws MojoExecutionException
+    {
+        Context context = new VelocityContext(baseContext);
+        context.put("component", component);
+
+        if (Boolean.TRUE.equals(component.isTemplate()))
+        {
+            String source = this.getInnerSourceCode(builder, component);
+            
+            if (source != null && !"".equals(source))
+            {
+                context.put("innersource", source);
+            }
+        }        
+        
+        Writer writer = null;
+        File outFile = null;
+
+        try
+        {
+            outFile = new File(generatedSourceDirectory, StringUtils.replace(
+                    component.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;
+        }
+    }
+        
+    /**
+     * This method extract from component scanned sourceClass, the parts
+     * which we need to move to generated class as a single String using Qdox.
+     * 
+     * Ignore code that has a \@JSFExclude or \@JSFProperty Doclet or Annotation
+     * 
+     * @param component
+     * @return
+     */
+    private String getInnerSourceCode(JavaDocBuilder builder, ComponentMeta component)
+    {   
+        StringWriter writer = new StringWriter();
+        
+        JavaClass sourceClass = builder.getClassByName(component.getSourceClassName());
+        
+        JavaField [] fields = sourceClass.getFields();
+
+        //Include the fields defined
+        for (int i = 0; i < fields.length; i++)
+        {            
+            JavaField field = fields[i];
+            
+            DocletTag tag = field.getTagByName("JSFExclude");
+            Annotation anno = getAnnotation(field, "JSFExclude");
+            
+            if (!(tag == null && anno == null))
+            {
+                continue;
+            }
+                        
+            if (!isExcludedField(field.getName()))
+            {
+                writer.append("    ");
+                writer.append(field.getDeclarationSignature(true));
+                String initExpr = field.getInitializationExpression();
+                initExpr = cleanInitializationExpression(initExpr);
+                if (initExpr != null)
+                {
+                    writer.append(" = ");
+                    writer.append(initExpr);
+                }                
+                writer.append(';');
+                writer.append('\n');
+            }
+        }
+        
+        JavaMethod [] methods = sourceClass.getMethods();
+        for (int i = 0; i < methods.length; i++)
+        {
+            JavaMethod method = methods[i];
+
+            DocletTag tag = method.getTagByName("JSFExclude");
+            Annotation anno = getAnnotation(method, "JSFExclude");
+            
+            if (!(tag == null && anno == null))
+            {
+                continue;
+            }
+            
+            tag = method.getTagByName("JSFProperty", false);
+            anno = getAnnotation(method, "JSFProperty");
+            
+            if ( (tag == null && anno == null) || !method.isAbstract())
+            {              
+                //Get declaration signature in a way that we don't need
+                //to declare imports.
+                String declaration = method.getDeclarationSignature(true);
+                
+                //Fix for qdox 1.6.3: remove code 
+                int index = declaration.indexOf(')');
+                if (index != -1)
+                {
+                    declaration = declaration.substring(0,index+1);
+                }
+                
+                //Append exception in full form
+                Type [] exceptions = method.getExceptions();
+                if (exceptions != null && exceptions.length != 0)
+                {
+                    declaration = declaration + " throws ";                    
+                    for (int j = 0; j < exceptions.length; j++)
+                    {
+                        declaration = declaration + exceptions[j].getJavaClass().getFullyQualifiedName();
+                    }
+                }
+                
+                writer.append("    ");
+                writer.append(declaration);
+                writer.append('\n');
+                writer.append("    ");
+                writer.append('{');
+                writer.append(method.getSourceCode());
+                writer.append('}');
+                writer.append('\n');
+                writer.append('\n');
+            }
+            
+        }
+                
+        return writer.toString();
+    }
+    
+    private boolean isExcludedField(String name)
+    {
+        return (name.equals("COMPONENT_TYPE") || 
+                name.equals("DEFAULT_RENDERER_TYPE") ||
+                name.equals("COMPONENT_FAMILY") );
+    }
+
+    /**
+     * Clean up a field initialisation expression returned by qdox.
+     * <p>
+     * When a class has "int foo = 1;" then the initialisation expression
+     * is the bit after the equals sign. Unfortunately qdox tends to return
+     * a lot of garbage stuff in there. In particular, if there is no
+     * initialisation expression, then qdox can return a string with
+     * whitespace (not a null or empty string). 
+     * <p>
+     * In addition, if there are comments *before* a field declaration,
+     * they appear inside the initialisation text (this is just broken
+     * behaviour in qdox). Ideally we would move them to above the field
+     * declaration where they belong. However that is complicated and
+     * fragile, so we just discard them here.
+     */
+    static String cleanInitializationExpression(String expr)
+    {
+        expr = StringUtils.trim(expr);
+        if (StringUtils.isEmpty(expr))
+        {
+            return null;
+        }
+        
+        // split on linefeeds
+        // trim each separately
+        // remove any comment chars
+        
+        if (expr.contains("\n"))
+        {
+            StringBuffer buf = new StringBuffer(100);
+            String[] lines = StringUtils.split(expr, "\n");
+            for(int i=0; i<lines.length; ++i)
+            {
+                String line = lines[i];
+                line = StringUtils.trim(line);
+                if (!line.startsWith("//") && !StringUtils.isEmpty(line))
+                {
+                    if (buf.length()> 0)
+                    {
+                        buf.append(" ");
+                    }
+                    buf.append(line);
+                }
+            }
+            
+            expr = buf.toString();
+        }
+        
+        if (expr.startsWith("//"))
+        {
+            return null;
+        }
+
+        if (StringUtils.isEmpty(expr))
+        {
+            return null;
+        }
+
+        return expr;
+    }
+
+    /**
+     * TODO: Copied from QdoxModelBuilder!
+     * 
+     * @param entity
+     * @param annoName
+     * @return
+     */
+    private Annotation getAnnotation(AbstractJavaEntity entity, String annoName)
+    {
+        Annotation[] annos = entity.getAnnotations();
+        if (annos == null)
+        {
+            return null;
+        }
+        // String wanted = ANNOTATION_BASE + "." + annoName;
+        for (int i = 0; i < annos.length; ++i)
+        {
+            Annotation thisAnno = annos[i];
+            // Ideally, here we would check whether the fully-qualified name of
+            // the annotation
+            // class matches ANNOTATION_BASE + "." + annoName. However it
+            // appears that qdox 1.6.3
+            // does not correctly expand @Foo using the class import statements;
+            // method
+            // Annotation.getType.getJavaClass.getFullyQualifiedName still just
+            // returns the short
+            // class name. So for now, just check for the short name.
+            String thisAnnoName = thisAnno.getType().getJavaClass().getName();
+            
+            //Make short name for recognizing, if returns long
+            int containsPoint = thisAnnoName.lastIndexOf('.');
+            if (containsPoint != -1)
+            {
+                thisAnnoName = thisAnnoName.substring(containsPoint+1);
+            }
+            if (thisAnnoName.equals(annoName))
+            {
+                return thisAnno;
+            }
+        }
+        return null;
+    }    
+
+    private String _getTemplateName()
+    {
+        if (templateComponentName == null)
+        {
+            if (_is12())
+            {
+                return "componentClass12.vm";
+            }
+            else
+            {
+                return "componentClass11.vm";
+            }
+        }
+        else
+        {
+            return templateComponentName;
+        }
+    }
+    
+    private boolean _is12()
+    {
+        return "1.2".equals(jsfVersion) || "12".equals(jsfVersion);
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConfigMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConfigMojo.java
new file mode 100644
index 0000000..dc422a1
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConfigMojo.java
@@ -0,0 +1,366 @@
+/*
+ *  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.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+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.utils.BuildException;
+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.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+import org.codehaus.plexus.util.xml.Xpp3DomWriter;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Creates taglib (tld) and faces-config files.
+ * <p>
+ * This Mojo actually provides a generic goal that will run a configurable
+ * velocity template file and generate a single output file. The template is
+ * passed the full metadata model object, and can select from the model whatever
+ * data it wants.
+ * </p>
+ * <p>
+ * The execution can be configured with:
+ * <ul>
+ * <li>The name of the input template to be executed</li>
+ * <li>The name of the output file to be created</li>
+ * <li>Any number of variables which are accessable from the template
+ * (string values only)</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The executed template has the following variables available to it:
+ * <ul>
+ * <li>model: the full metadata model for this project</li>
+ * <li>modelIds: specifies which items from the model should be processed</li>
+ * <li>baseContent: the full text of the contents of the "xmlBaseFile" (if any)</li>
+ * <li>utils: an instance of MyfacesUtils that provides static helper methods</li>
+ * <li>and whatever (name,value) pairs were configured via the "params" property
+ * of this mojo.</li>
+ * </ul>
+ * </p>
+ * 
+ * @requiresDependencyResolution compile
+ * @goal make-config
+ * @phase generate-sources
+ */
+public class MakeConfigMojo extends AbstractMojo
+{
+    /**
+     * The current maven project (auto-injected by Maven).
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * The current maven project (auto-injected by Maven).
+     * 
+     * TODO: this default value looks wrong. What should really be here?
+     * 
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+     * @readonly
+     */
+    private File buildDirectory;
+
+    /**
+     * Name of the file from which the metadata model passed to the
+     * template will be read. This file is typically generated by an earlier
+     * execution of the BuildMetaDataMojo goal for the same maven project.
+     * 
+     * @parameter
+     */
+    private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+    /**
+     * Specifies the name of the output file to be created.
+     * 
+     * @parameter
+     */
+    private String xmlFile = "META-INF/faces-config.xml";
+    
+    /**
+     * A list of metadata model ids.
+     * <p>
+     * If not defined, then this defaults to a list containing just one string whose
+     * value is the same as the current maven project's artifactId.
+     * </p>
+     * <p>
+     * The complete metadata model is passed to the velocity template. This contains 
+     * data about not just the model items defined in the calling project, but also
+     * about items imported from other projects. Each item in the model is
+     * labelled with a "model id" indicating which project it was defined by.
+     * </p>
+     * <p>
+     * This list of model ids is also passed to the template. The template can
+     * then use that data to select the relevant items from the full model.
+     * </p>
+     * 
+     * @parameter
+     */
+    private List modelIds;
+            
+    /**
+     * The base directory used when resolving references to external files from
+     * velocity #include and #parse commands within the executed template.
+     * 
+     * @parameter expression="src/main/resources/META-INF"
+     */
+    private File templateSourceDirectory;
+    
+    /**
+     * When defined, specifies an xml file whose top-level elements are to be copied
+     * directly into the created file.
+     * <p>
+     * This allows a hand-written file to be created containing data that cannot be
+     * automatically generated. All content beneath the root element of the specified
+     * file (but not the root element itself) is placed into a Velocity variable
+     * named "baseContent" that the template can reference.
+     * </p>
+     * <p>
+     * The template can do whatever it wants with this variable, but it is expected
+     * that the template will simply output this immediately after writing the
+     * root element of the output xml file.
+     * file.
+     * </p>
+     * <p>
+     * Note that any attributes or namespaces defined on the root element of the
+     * xmlBaseFile are ignored.
+     * </p>
+     * 
+     * @parameter expression="src/main/conf/META-INF/faces-config-base.xml"
+     */    
+    private File xmlBaseFile;
+
+    /**
+     * Specifies the Velocity template file to be executed.
+     * 
+     * @parameter expression="faces-config11.vm"
+     */
+    private String templateFile;
+    
+    /**
+     * A map of (name, value) pairs to be made available as Velocity variables
+     * for the executed template to access.
+     * 
+     * @parameter
+     */
+    private Map params;
+        
+    /**
+     * Execute the Mojo.
+     * <p>
+     * The metadata model is loaded, and the specified template is executed with
+     * any template output being written to the specified output file.
+     * </p>
+     */
+    public void execute() throws MojoExecutionException
+    {
+        try
+        {
+            if (modelIds == null)
+            {
+                modelIds = new ArrayList();
+                modelIds.add(project.getArtifactId());
+            }
+
+            // Load the metadata file from an xml file (presumably generated
+            // by an earlier execution of the build-metadata goal.
+            Model model = IOUtils.loadModel(new File(buildDirectory,
+                    metadataFile));
+
+            // Flatten the model so that the template can access every property
+            // of each model item directly, even when the property is actually
+            // defined on an ancestor class or interface.
+            new Flattener(model).flatten();
+
+            generateConfigFromVelocity(model);
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Error during config generation", e);
+        }
+        catch (BuildException e)
+        {
+            throw new MojoExecutionException("Error during config generation", e);
+        }
+    }
+    
+    private void generateConfigFromVelocity(Model model) throws IOException,
+        MojoExecutionException
+    {    
+        VelocityEngine velocityEngine = initVelocity();
+
+        VelocityContext baseContext = new VelocityContext();
+        baseContext.put("utils", new MyfacesUtils());
+        
+        String baseContent = "";
+        
+        if (xmlBaseFile != null && xmlBaseFile.exists())
+        {
+            getLog().info("using base content file: "+xmlBaseFile.getPath());
+            
+            Reader reader = null;
+            try
+            {
+                reader = new FileReader(xmlBaseFile);
+                Xpp3Dom root = Xpp3DomBuilder.build(reader);
+                
+                StringWriter writer = new StringWriter();
+                
+                Xpp3Dom [] children = root.getChildren();
+                
+                for (int i = 0; i< children.length; i++)
+                {
+                    Xpp3Dom dom = children[i];
+                    Xpp3DomWriter.write(writer, dom);
+                    writer.write('\n');
+                }
+                baseContent = writer.toString();
+                writer.close();
+            }
+            catch (XmlPullParserException e)
+            {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+            finally
+            {
+                reader.close();
+            }
+        }
+        
+        baseContext.put("baseContent", baseContent);
+        
+        baseContext.put("model", model);
+        
+        baseContext.put("modelIds", modelIds);
+        
+        if (params != null)
+        {
+            //Load all parameters to the context, so the template can
+            //load it. This allow to generate any config file we want
+            //(faces-config, tld, facelet,....)
+            for (Iterator it = params.keySet().iterator(); it.hasNext();)
+            {
+                String key = (String) it.next();
+                baseContext.put(key,params.get(key));
+            }
+        }
+        
+        Writer writer = null;
+        File outFile = null;
+        
+        try
+        {
+            outFile = new File(buildDirectory, xmlFile);
+            
+            if ( !outFile.getParentFile().exists() )
+            {
+                outFile.getParentFile().mkdirs();
+            }
+            
+            writer = new OutputStreamWriter(new FileOutputStream(outFile));
+            
+            Template template = velocityEngine.getTemplate(templateFile);
+            
+            template.merge(baseContext, writer);
+
+            writer.flush();
+        }
+        catch (ResourceNotFoundException e)
+        {
+            throw new MojoExecutionException(
+                    "Error merging velocity templates: " + e.getMessage(), e);
+        }
+        catch (ParseErrorException e)
+        {
+            throw new MojoExecutionException(
+                    "Error merging velocity templates: " + e.getMessage(), e);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException(
+                    "Error merging velocity templates: " + e.getMessage(), e);
+        }
+        finally
+        {
+            IOUtil.close(writer);
+            writer = null;
+        }        
+    }
+
+    private VelocityEngine initVelocity() throws MojoExecutionException
+    {
+
+        Properties p = new Properties();
+
+        p.setProperty( "resource.loader", "file, class" );
+        p.setProperty( "file.resource.loader.class",
+                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+        p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+        p.setProperty( "class.resource.loader.class",
+                "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+        p.setProperty( "class.resource.loader.path", "META-INF");            
+        p.setProperty( "velocimacro.library", "xmlMacros.vm");
+        p.setProperty( "velocimacro.permissions.allow.inline","true");
+        p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+        p.setProperty( "directive.foreach.counter.initial.value","0");
+        p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+        "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+                        
+        VelocityEngine velocityEngine = new VelocityEngine();
+                
+        try
+        {
+            velocityEngine.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error creating VelocityEngine", e);
+        }
+        
+        return velocityEngine;
+    }
+    
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConverterTagsMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConverterTagsMojo.java
new file mode 100644
index 0000000..35c36a9
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConverterTagsMojo.java
@@ -0,0 +1,384 @@
+/*
+ *  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 java.util.Properties;
+import java.util.logging.Logger;
+
+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.ConverterMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.BuildException;
+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;
+
+/**
+ * Maven goal to generate java source code for Component tag classes.
+ * 
+ * @version $Id$
+ * @requiresDependencyResolution compile
+ * @goal make-converter-tags
+ * @phase generate-sources
+ */
+public class MakeConverterTagsMojo extends AbstractMojo
+{
+    final Logger log = Logger.getLogger(MakeConverterTagsMojo.class.getName());
+
+    /**
+     * Injected Maven project.
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @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";
+
+    /**
+     * @parameter expression="src/main/resources/META-INF"
+     */
+    private File templateSourceDirectory;
+    
+    /**
+     * 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;
+
+    /**
+     * @parameter 
+     */
+    private String templateTagName;
+
+    /**
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+     * @required
+     */
+    private File generatedSourceDirectory;
+
+    /**
+     * Only generate tag classes that contains that package prefix
+     * 
+     * @parameter
+     */
+    private String packageContains;
+
+    /**
+     * Only generate tag classes that its component starts with this type prefix
+     * 
+     * @parameter
+     */
+    private String typePrefix;
+    
+    /**
+     * @parameter
+     */
+    private boolean force;
+
+    /**
+     * @parameter
+     */
+    private boolean suppressListenerMethods;
+
+    /**
+     * @parameter
+     */
+    private String jsfVersion;
+    
+    /**
+     * @parameter
+     */
+    private List modelIds;
+    
+    /**
+     * 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 components", e);
+        }
+        catch (BuildException e)
+        {
+            throw new MojoExecutionException("Error generating components", e);
+        }
+    }
+        
+    private VelocityEngine initVelocity() throws MojoExecutionException
+    {
+
+        Properties p = new Properties();
+
+        p.setProperty( "resource.loader", "file, class" );
+        p.setProperty( "file.resource.loader.class",
+                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+        p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+        p.setProperty( "class.resource.loader.class",
+                "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+        p.setProperty( "class.resource.loader.path", "META-INF");            
+        p.setProperty( "velocimacro.library", "tagClassMacros11.vm");
+        p.setProperty( "velocimacro.permissions.allow.inline","true");
+        p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+        p.setProperty( "directive.foreach.counter.initial.value","0");
+        p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+        "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+        
+        File template = new File(templateSourceDirectory, _getTemplateTagName());
+        
+        if (template.exists())
+        {
+            log.info("Using template from file loader: "+template.getPath());
+        }
+        else
+        {
+            log.info("Using template from class loader: META-INF/"+_getTemplateTagName());
+        }
+                
+        VelocityEngine velocityEngine = new VelocityEngine();
+                
+        try
+        {
+            velocityEngine.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error creating VelocityEngine", e);
+        }
+        
+        return velocityEngine;
+    }
+
+    /**
+     * Generates parsed components.
+     */
+    private void generateConverters(Model model) throws IOException,
+            MojoExecutionException
+    {
+        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.getTagClass() != null)
+            {
+                File f = new File(mainSourceDirectory, StringUtils.replace(
+                    converter.getTagClass(), ".", "/")+".java");
+                
+                if (!f.exists() && canGenerateConverterTag(converter))
+                {
+                    if (mainSourceDirectory2 != null)
+                    {
+                        File f2 = new File(mainSourceDirectory2, StringUtils.replace(
+                                converter.getTagClass(), ".", "/")+".java");
+                        if (f2.exists())
+                        {
+                            //Skip
+                            continue;
+                        }
+                    }
+                    log.info("Generating tag class:"+converter.getTagClass());
+                    _generateConverter(velocityEngine, converter,baseContext);
+                }
+            }
+        }
+        //throw new MojoExecutionException("stopping..");
+    }
+    
+    public boolean canGenerateConverterTag(ConverterMeta component)
+    {
+        if ( modelIds.contains(component.getModelId())
+                && includePackage(component)
+                && includeId(component))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    public boolean includePackage(ConverterMeta converter)
+    {
+        if (packageContains != null)
+        {
+            if (MyfacesUtils.getPackageFromFullClass(converter.getTagClass()).startsWith(packageContains))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+
+    public boolean includeId(ConverterMeta converter)
+    {
+        if (typePrefix != null)
+        {
+            if (converter.getConverterId().startsWith(typePrefix))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+
+
+    /**
+     * Generates a parsed component.
+     * 
+     * @param converter
+     *            the parsed component metadata
+     */
+    private void _generateConverter(VelocityEngine velocityEngine, 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.getTagClass(), ".", "/")+".java");
+
+            if ( !outFile.getParentFile().exists() )
+            {
+                outFile.getParentFile().mkdirs();
+            }
+
+            writer = new OutputStreamWriter(new FileOutputStream(outFile));
+
+            Template template = velocityEngine.getTemplate(_getTemplateTagName());
+                        
+            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 _getTemplateTagName()
+    {
+        if (templateTagName == null)
+        {
+            if (_is12())
+            {
+                return "tagConverterClass12.vm";
+            }
+            else
+            {
+                return "tagConverterClass11.vm";
+            }
+        }
+        else
+        {
+            return templateTagName;
+        }
+    }
+
+    private boolean _is12()
+    {
+        return "1.2".equals(jsfVersion) || "12".equals(jsfVersion);
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeTagsMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeTagsMojo.java
new file mode 100644
index 0000000..dbcefcb
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeTagsMojo.java
@@ -0,0 +1,384 @@
+/*
+ *  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 java.util.Properties;
+import java.util.logging.Logger;
+
+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.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.BuildException;
+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;
+
+/**
+ * Maven goal to generate java source code for Component tag classes.
+ * 
+ * @version $Id$
+ * @requiresDependencyResolution compile
+ * @goal make-tags
+ * @phase generate-sources
+ */
+public class MakeTagsMojo extends AbstractMojo
+{
+    final Logger log = Logger.getLogger(MakeTagsMojo.class.getName());
+
+    /**
+     * Injected Maven project.
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @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";
+
+    /**
+     * @parameter expression="src/main/resources/META-INF"
+     */
+    private File templateSourceDirectory;
+    
+    /**
+     * 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;
+
+    /**
+     * @parameter 
+     */
+    private String templateTagName;
+
+    /**
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+     * @required
+     */
+    private File generatedSourceDirectory;
+
+    /**
+     * Only generate tag classes that contains that package prefix
+     * 
+     * @parameter
+     */
+    private String packageContains;
+
+    /**
+     * Only generate tag classes that its component starts with this type prefix
+     * 
+     * @parameter
+     */
+    private String typePrefix;
+    
+    /**
+     * @parameter
+     */
+    private boolean force;
+
+    /**
+     * @parameter
+     */
+    private boolean suppressListenerMethods;
+
+    /**
+     * @parameter
+     */
+    private String jsfVersion;
+    
+    /**
+     * @parameter
+     */
+    private List modelIds;
+    
+    /**
+     * 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();
+            generateComponents(model);
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Error generating components", e);
+        }
+        catch (BuildException e)
+        {
+            throw new MojoExecutionException("Error generating components", e);
+        }
+    }
+        
+    private VelocityEngine initVelocity() throws MojoExecutionException
+    {
+
+        Properties p = new Properties();
+
+        p.setProperty( "resource.loader", "file, class" );
+        p.setProperty( "file.resource.loader.class",
+                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+        p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+        p.setProperty( "class.resource.loader.class",
+                "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+        p.setProperty( "class.resource.loader.path", "META-INF");            
+        p.setProperty( "velocimacro.library", "tagClassMacros11.vm");
+        p.setProperty( "velocimacro.permissions.allow.inline","true");
+        p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+        p.setProperty( "directive.foreach.counter.initial.value","0");
+        p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+        "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+        
+        File template = new File(templateSourceDirectory, _getTemplateTagName());
+        
+        if (template.exists())
+        {
+            log.info("Using template from file loader: "+template.getPath());
+        }
+        else
+        {
+            log.info("Using template from class loader: META-INF/"+_getTemplateTagName());
+        }
+                
+        VelocityEngine velocityEngine = new VelocityEngine();
+                
+        try
+        {
+            velocityEngine.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error creating VelocityEngine", e);
+        }
+        
+        return velocityEngine;
+    }
+
+    /**
+     * Generates parsed components.
+     */
+    private void generateComponents(Model model) throws IOException,
+            MojoExecutionException
+    {
+        VelocityEngine velocityEngine = initVelocity();
+
+        VelocityContext baseContext = new VelocityContext();
+        baseContext.put("utils", new MyfacesUtils());
+        
+        for (Iterator it = model.getComponents().iterator(); it.hasNext();)
+        {
+            ComponentMeta component = (ComponentMeta) it.next();
+            
+            if (component.getTagClass() != null)
+            {
+                File f = new File(mainSourceDirectory, StringUtils.replace(
+                    component.getTagClass(), ".", "/")+".java");
+                
+                if (!f.exists() && canGenerateComponentTag(component))
+                {
+                    if (mainSourceDirectory2 != null)
+                    {
+                        File f2 = new File(mainSourceDirectory2, StringUtils.replace(
+                                component.getTagClass(), ".", "/")+".java");
+                        if (f2.exists())
+                        {
+                            //Skip
+                            continue;
+                        }
+                    }
+                    log.info("Generating tag class:"+component.getTagClass());
+                    _generateComponent(velocityEngine, component,baseContext);
+                }
+            }
+        }
+        //throw new MojoExecutionException("stopping..");
+    }
+    
+    public boolean canGenerateComponentTag(ComponentMeta component)
+    {
+        if ( modelIds.contains(component.getModelId())
+                && includePackage(component)
+                && includeType(component))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    public boolean includePackage(ComponentMeta component)
+    {
+        if (packageContains != null)
+        {
+            if (component.getTagPackage().startsWith(packageContains))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+
+    public boolean includeType(ComponentMeta component)
+    {
+        if (typePrefix != null)
+        {
+            if (component.getType().startsWith(typePrefix))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+
+
+    /**
+     * Generates a parsed component.
+     * 
+     * @param component
+     *            the parsed component metadata
+     */
+    private void _generateComponent(VelocityEngine velocityEngine, ComponentMeta component, VelocityContext baseContext)
+            throws MojoExecutionException
+    {
+
+        Context context = new VelocityContext(baseContext);
+        context.put("component", component);
+
+        Writer writer = null;
+        File outFile = null;
+
+        try
+        {
+            outFile = new File(generatedSourceDirectory, StringUtils.replace(
+                    component.getTagClass(), ".", "/")+".java");
+
+            if ( !outFile.getParentFile().exists() )
+            {
+                outFile.getParentFile().mkdirs();
+            }
+
+            writer = new OutputStreamWriter(new FileOutputStream(outFile));
+
+            Template template = velocityEngine.getTemplate(_getTemplateTagName());
+                        
+            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 _getTemplateTagName()
+    {
+        if (templateTagName == null)
+        {
+            if (_is12())
+            {
+                return "tagClass12.vm";
+            }
+            else
+            {
+                return "tagClass11.vm";
+            }
+        }
+        else
+        {
+            return templateTagName;            
+        }        
+    }
+
+    private boolean _is12()
+    {
+        return "1.2".equals(jsfVersion) || "12".equals(jsfVersion);
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorTagsMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorTagsMojo.java
new file mode 100644
index 0000000..e35c970
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorTagsMojo.java
@@ -0,0 +1,384 @@
+/*
+ *  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 java.util.Properties;
+import java.util.logging.Logger;
+
+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.ValidatorMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.BuildException;
+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;
+
+/**
+ * Maven goal to generate java source code for Component tag classes.
+ * 
+ * @version $Id$
+ * @requiresDependencyResolution compile
+ * @goal make-validator-tags
+ * @phase generate-sources
+ */
+public class MakeValidatorTagsMojo extends AbstractMojo
+{
+    final Logger log = Logger.getLogger(MakeValidatorTagsMojo.class.getName());
+
+    /**
+     * Injected Maven project.
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @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";
+
+    /**
+     * @parameter expression="src/main/resources/META-INF"
+     */
+    private File templateSourceDirectory;
+    
+    /**
+     * 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;
+
+    /**
+     * @parameter 
+     */
+    private String templateTagName;
+
+    /**
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+     * @required
+     */
+    private File generatedSourceDirectory;
+
+    /**
+     * Only generate tag classes that contains that package prefix
+     * 
+     * @parameter
+     */
+    private String packageContains;
+
+    /**
+     * Only generate tag classes that its component starts with this type prefix
+     * 
+     * @parameter
+     */
+    private String typePrefix;
+    
+    /**
+     * @parameter
+     */
+    private boolean force;
+
+    /**
+     * @parameter
+     */
+    private boolean suppressListenerMethods;
+
+    /**
+     * @parameter
+     */
+    private String jsfVersion;
+    
+    /**
+     * @parameter
+     */
+    private List modelIds;
+    
+    /**
+     * 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();
+            generateValidators(model);
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Error generating components", e);
+        }
+        catch (BuildException e)
+        {
+            throw new MojoExecutionException("Error generating components", e);
+        }
+    }
+        
+    private VelocityEngine initVelocity() throws MojoExecutionException
+    {
+
+        Properties p = new Properties();
+
+        p.setProperty( "resource.loader", "file, class" );
+        p.setProperty( "file.resource.loader.class",
+                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+        p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+        p.setProperty( "class.resource.loader.class",
+                "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+        p.setProperty( "class.resource.loader.path", "META-INF");            
+        p.setProperty( "velocimacro.library", "tagClassMacros11.vm");
+        p.setProperty( "velocimacro.permissions.allow.inline","true");
+        p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+        p.setProperty( "directive.foreach.counter.initial.value","0");
+        p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+        "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+        
+        File template = new File(templateSourceDirectory, _getTemplateTagName());
+        
+        if (template.exists())
+        {
+            log.info("Using template from file loader: "+template.getPath());
+        }
+        else
+        {
+            log.info("Using template from class loader: META-INF/"+_getTemplateTagName());
+        }
+                
+        VelocityEngine velocityEngine = new VelocityEngine();
+                
+        try
+        {
+            velocityEngine.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error creating VelocityEngine", e);
+        }
+        
+        return velocityEngine;
+    }
+
+    /**
+     * Generates parsed components.
+     */
+    private void generateValidators(Model model) throws IOException,
+            MojoExecutionException
+    {
+        VelocityEngine velocityEngine = initVelocity();
+
+        VelocityContext baseContext = new VelocityContext();
+        baseContext.put("utils", new MyfacesUtils());
+        
+        for (Iterator it = model.getValidators().iterator(); it.hasNext();)
+        {
+            ValidatorMeta validator = (ValidatorMeta) it.next();
+            
+            if (validator.getTagClass() != null)
+            {
+                File f = new File(mainSourceDirectory, StringUtils.replace(
+                    validator.getTagClass(), ".", "/")+".java");
+                
+                if (!f.exists() && canGenerateValidatorTag(validator))
+                {
+                    if (mainSourceDirectory2 != null)
+                    {
+                        File f2 = new File(mainSourceDirectory2, StringUtils.replace(
+                                validator.getTagClass(), ".", "/")+".java");
+                        if (f2.exists())
+                        {
+                            //Skip
+                            continue;
+                        }
+                    }
+                    log.info("Generating tag class:"+validator.getTagClass());
+                    _generateValidator(velocityEngine, validator,baseContext);
+                }
+            }
+        }
+        //throw new MojoExecutionException("stopping..");
+    }
+    
+    public boolean canGenerateValidatorTag(ValidatorMeta component)
+    {
+        if ( modelIds.contains(component.getModelId())
+                && includePackage(component)
+                && includeId(component))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    public boolean includePackage(ValidatorMeta validator)
+    {
+        if (packageContains != null)
+        {
+            if (MyfacesUtils.getPackageFromFullClass(validator.getTagClass()).startsWith(packageContains))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+
+    public boolean includeId(ValidatorMeta validator)
+    {
+        if (typePrefix != null)
+        {
+            if (validator.getValidatorId().startsWith(typePrefix))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+
+
+    /**
+     * Generates a parsed component.
+     * 
+     * @param validator
+     *            the parsed component metadata
+     */
+    private void _generateValidator(VelocityEngine velocityEngine, ValidatorMeta validator, VelocityContext baseContext)
+            throws MojoExecutionException
+    {
+
+        Context context = new VelocityContext(baseContext);
+        context.put("validator", validator);
+
+        Writer writer = null;
+        File outFile = null;
+
+        try
+        {
+            outFile = new File(generatedSourceDirectory, StringUtils.replace(
+                    validator.getTagClass(), ".", "/")+".java");
+
+            if ( !outFile.getParentFile().exists() )
+            {
+                outFile.getParentFile().mkdirs();
+            }
+
+            writer = new OutputStreamWriter(new FileOutputStream(outFile));
+
+            Template template = velocityEngine.getTemplate(_getTemplateTagName());
+                        
+            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 _getTemplateTagName()
+    {
+        if (templateTagName == null)
+        {
+            if (_is12())
+            {
+                return "tagValidatorClass12.vm";
+            }
+            else
+            {
+                return "tagValidatorClass11.vm";
+            }
+        }
+        else
+        {
+            return templateTagName;
+        }
+    }
+
+    private boolean _is12()
+    {
+        return "1.2".equals(jsfVersion) || "12".equals(jsfVersion);
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorsMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorsMojo.java
new file mode 100644
index 0000000..6691f6d
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorsMojo.java
@@ -0,0 +1,376 @@
+/*
+ *  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 java.util.Properties;
+import java.util.logging.Logger;
+
+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.ValidatorMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.BuildException;
+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 Validator classes.
+ * 
+ * @version $Id$
+ * @requiresDependencyResolution compile
+ * @goal make-validators
+ * @phase generate-sources
+ */
+public class MakeValidatorsMojo extends AbstractMojo
+{
+    final Logger log = Logger.getLogger(MakeValidatorsMojo.class.getName());
+
+    /**
+     * Injected Maven project.
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @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";
+
+    /**
+     * @parameter expression="src/main/resources/META-INF"
+     */
+    private File templateSourceDirectory;
+
+    /**
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+     */
+    private File generatedSourceDirectory;
+
+    /**
+     * @parameter
+     */
+    private String packageContains;
+
+    /**
+     * @parameter
+     */
+    private boolean force;
+
+    /**
+     * @parameter
+     */
+    private boolean suppressListenerMethods;
+
+    /**
+     * @parameter
+     */
+    private String jsfVersion;
+    
+    /**
+     * @parameter
+     */
+    private List modelIds;
+
+    /**
+     * @parameter 
+     */
+    private String templateValidatorName;
+    
+    /**
+     * 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();
+            generateValidators(model);
+        }
+        catch (IOException e)
+        {
+            throw new MojoExecutionException("Error generating validators", e);
+        }
+        catch (BuildException e)
+        {
+            throw new MojoExecutionException("Error generating validators", e);
+        }
+    }
+    
+    
+    private VelocityEngine initVelocity() throws MojoExecutionException
+    {
+
+        Properties p = new Properties();
+
+        p.setProperty( "resource.loader", "file, class" );
+        p.setProperty( "file.resource.loader.class",
+                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+        p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+        p.setProperty( "class.resource.loader.class",
+                "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+        p.setProperty( "class.resource.loader.path", "META-INF");            
+        p.setProperty( "velocimacro.library", "validatorClassMacros11.vm");
+        p.setProperty( "velocimacro.permissions.allow.inline","true");
+        p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+        p.setProperty( "directive.foreach.counter.initial.value","0");
+        p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+        "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+        
+        File template = new File(templateSourceDirectory, _getTemplateName());
+        
+        if (template.exists())
+        {
+            log.info("Using template from file loader: "+template.getPath());
+        }
+        else
+        {
+            log.info("Using template from class loader: META-INF/"+_getTemplateName());
+        }
+                
+        VelocityEngine velocityEngine = new VelocityEngine();
+                
+        try
+        {
+            velocityEngine.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error creating VelocityEngine", e);
+        }
+        
+        return velocityEngine;
+    }
+    
+
+    /**
+     * Generates parsed validators.
+     */
+    private void generateValidators(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.getValidators().iterator(); it.hasNext();)
+        {
+            ValidatorMeta validator = (ValidatorMeta) it.next();
+            
+            if (validator.getClassName() != null)
+            {
+                File f = new File(mainSourceDirectory, StringUtils.replace(
+                    validator.getClassName(), ".", "/")+".java");
+                                
+                if (!f.exists() && canGenerateValidator(validator))
+                {
+                    if (mainSourceDirectory2 != null)
+                    {
+                        File f2 = new File(mainSourceDirectory2, StringUtils.replace(
+                                validator.getClassName(), ".", "/")+".java");
+                        if (f2.exists())
+                        {
+                            //Skip
+                            continue;
+                        }
+                    }
+                    log.info("Generating validator class:"+validator.getClassName());
+                    _generateValidator(velocityEngine, builder,validator,baseContext);
+                }
+            }
+        }        
+    }
+    
+    public boolean canGenerateValidator(ValidatorMeta validator)
+    {
+        if ( modelIds.contains(validator.getModelId())
+                && includePackage(validator))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    public boolean includePackage(ValidatorMeta validator)
+    {
+        if (packageContains != null)
+        {
+            if (MyfacesUtils.getPackageFromFullClass(validator.getClassName()).startsWith(packageContains))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }        
+    }
+    
+    
+    /**
+     * Generates a parsed validator.
+     * 
+     * @param validator
+     *            the parsed validator metadata
+     */
+    private void _generateValidator(VelocityEngine velocityEngine,
+            JavaDocBuilder builder,
+            ValidatorMeta validator, VelocityContext baseContext)
+            throws MojoExecutionException
+    {
+        Context context = new VelocityContext(baseContext);
+        context.put("validator", validator);
+        
+        Writer writer = null;
+        File outFile = null;
+
+        try
+        {
+            outFile = new File(generatedSourceDirectory, StringUtils.replace(
+                    validator.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 (templateValidatorName == null)
+        {
+            if (_is12())
+            {
+                return "validatorClass12.vm";
+            }
+            else
+            {
+                return "validatorClass11.vm";
+            }
+        }
+        else
+        {
+            return templateValidatorName;
+        }
+    }
+    
+    private boolean _is12()
+    {
+        return "1.2".equals(jsfVersion) || "12".equals(jsfVersion);
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/ModelBuilder.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/ModelBuilder.java
new file mode 100644
index 0000000..74a81db
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/ModelBuilder.java
@@ -0,0 +1,61 @@
+/*
+ *  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 org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+
+/**
+ * An interface that is implemented by classes that are capable of collecting
+ * metadata about JSF components, converters, validators, etc.
+ * <p>
+ * A ModelBuilder implementation might read xml files, or scan source code for
+ * annotations, or read data from a database, or any number of possible
+ * approaches. All that matters is that it makes a series of calls to a Model
+ * object to add information.
+ * <p>
+ * ModelBuilder implementations may be run as a chain, ie one instance used to
+ * populate the Model object with some objects, then a second instance used to
+ * add more data or modify the data already in the model.
+ */
+public interface ModelBuilder
+{
+    /**
+     * Given a model (which might already be partly populated with data, add
+     * information about JSF artifacts.
+     */
+    public void buildModel(Model model, MavenProject project)
+            throws MojoExecutionException;
+
+    /**
+     * Given a model (which might already be partly populated with data, add
+     * information about JSF artifacts, indicating include and exclude
+     * rules
+     * 
+     * @since 1.0.2
+     * @param model the model to add the information
+     * @param project the maven project to analyze
+     * @param includes rules to include files
+     * @param excludes rules to exclude files
+     * @throws MojoExecutionException
+     */
+    public void buildModel(Model model, MavenProject project, String includes, String excludes)
+            throws MojoExecutionException;    
+}
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/io/PrettyWriter.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/io/PrettyWriter.java
new file mode 100644
index 0000000..08111fb
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/io/PrettyWriter.java
@@ -0,0 +1,178 @@
+/*
+ *  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.io;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+public class PrettyWriter extends PrintWriter
+{
+    public PrettyWriter(OutputStream out)
+    {
+        super(out);
+    }
+
+    public PrettyWriter(OutputStream out, boolean autoFlush)
+    {
+        super(out, autoFlush);
+    }
+
+    public PrettyWriter(Writer out)
+    {
+        super(out);
+    }
+
+    public PrettyWriter(Writer out, boolean autoFlush)
+    {
+        super(out, autoFlush);
+    }
+
+    public void indent()
+    {
+        _indentation++;
+    }
+
+    public void unindent()
+    {
+        _indentation--;
+    }
+
+    public void write(String string, int offset, int length)
+    {
+        if (_unlatchPending())
+        {
+            for (int i = 0; i < _indentation; i++)
+            {
+                super.write(TAB_INDENT, 0, 2);
+            }
+        }
+
+        super.write(string, offset, length);
+    }
+
+    public void write(char[] chars, int offset, int length)
+    {
+        if (_unlatchPending())
+        {
+            for (int i = 0; i < _indentation; i++)
+            {
+                super.write(TAB_INDENT_CHARS, 0, 2);
+            }
+        }
+
+        super.write(chars, offset, length);
+    }
+
+    public void println()
+    {
+        super.println();
+        _latchPending();
+    }
+
+    public void println(boolean x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    public void println(char x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    public void println(int x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    public void println(long x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    public void println(float x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    public void println(double x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    public void println(char[] x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    public void println(String x)
+    {
+        int fromIndex = 0;
+        for (int index = x.indexOf('\n'); index != -1 && index + 1 < x.length(); fromIndex = index + 1, index = x
+                .indexOf('\n', fromIndex))
+        {
+            super.println(x.substring(fromIndex, index));
+            _latchPending();
+        }
+
+        super.println(x.substring(fromIndex));
+        _latchPending();
+    }
+
+    public void println(Object x)
+    {
+        super.println(x);
+        _latchPending();
+    }
+
+    private boolean _unlatchPending()
+    {
+        boolean pending = _pending;
+        if (pending)
+        {
+            _pending = false;
+        }
+
+        return pending;
+    }
+
+    private boolean _latchPending()
+    {
+        boolean pending = _pending;
+        if (!pending)
+        {
+            _pending = true;
+        }
+
+        return !pending;
+    }
+
+    private int _indentation;
+    private boolean _pending = true;
+
+    private static final String TAB_INDENT = "  ";
+    private static final char[] TAB_INDENT_CHARS = TAB_INDENT.toCharArray();
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/io/XmlWriter.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/io/XmlWriter.java
new file mode 100644
index 0000000..f6abf67
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/io/XmlWriter.java
@@ -0,0 +1,219 @@
+/*
+ *  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.io;
+
+import java.io.PrintWriter;
+import java.util.Stack;
+
+/**
+ * Simple utility to help write out data structures in xml format, with pretty
+ * indenting.
+ */
+public class XmlWriter
+{
+    private static final String XML_CHARS = "<>&";
+
+    private PrintWriter out;
+    private Stack contexts = new Stack();
+    private int indent = 0;
+
+    // Is the current xml element still "open" for adding attributes,
+    // ie needs a ">" before adding nested text or child elements.
+    private boolean openElement = false;
+
+    private static class Context
+    {
+        String elementName;
+        boolean hasContent;
+
+        Context(String element)
+        {
+            elementName = element;
+        }
+    }
+
+    public XmlWriter(PrintWriter out)
+    {
+        this.out = out;
+    }
+
+    private void indent()
+    {
+        out.write("\n");
+        for (int i = 0; i < indent; ++i)
+        {
+            out.write("  ");
+        }
+    }
+
+    private void indentInc()
+    {
+        indent();
+        ++indent;
+    }
+
+    private void indentDec()
+    {
+        --indent;
+        indent();
+    }
+
+    private boolean containsXmlChars(String text)
+    {
+        for (int i = 0; i < XML_CHARS.length(); ++i)
+        {
+            if (text.indexOf(XML_CHARS.charAt(i)) >= 0)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void writeElement(String name, String body)
+    {
+        if (body == null)
+        {
+            return;
+        }
+
+        if (openElement)
+        {
+            out.write(">");
+            openElement = false;
+        }
+
+        indent();
+        out.write("<");
+        out.write(name);
+        out.write(">");
+
+        if (containsXmlChars(body))
+        {
+            // The text contains chars that need to be escaped. Rather than
+            // escape them one-by-one, just write the body in a CDATA section.
+
+            if (body.indexOf("\n") > 0)
+            {
+                // multi-line body, so it is most readable when the CDATA
+                // markers are against the left-hand margin
+                out.write("\n<![CDATA[\n");
+                out.write(body);
+                out.write("\n]]>");
+
+                // Write the end tag on the next line, correctly indented
+                indent();
+            }
+            else
+            {
+                // just a small body, so output it "inline"
+                out.write("<![CDATA[");
+                out.write(body);
+                out.write("]]>");
+            }
+        }
+        else
+        {
+            out.write(body);
+        }
+        out.write("</");
+        out.write(name);
+        out.write(">");
+
+        ((Context) contexts.peek()).hasContent = true;
+    }
+
+    public void writeElement(String name, boolean value)
+    {
+        writeElement(name, String.valueOf(value));
+    }
+
+    public void writeElement(String name, Boolean value)
+    {
+        if (value != null)
+        {
+            writeElement(name, value.toString());
+        }
+    }
+
+    public void beginElement(String name)
+    {
+        if (openElement)
+        {
+            out.write(">");
+        }
+        openElement = true;
+
+        indentInc();
+        out.write("<");
+        out.write(name);
+
+        if (!contexts.empty())
+        {
+            ((Context) contexts.peek()).hasContent = true;
+        }
+        contexts.push(new Context(name));
+
+    }
+
+    public void writeAttr(String name, String value)
+    {
+        if (value == null)
+        {
+            return;
+        }
+
+        if (!openElement)
+        {
+            throw new IllegalStateException("xml element not open");
+        }
+        out.write(" ");
+        out.write(name);
+        out.write("=");
+        out.write("\"");
+        out.write(value);
+        out.write("\"");
+    }
+
+    public void endElement(String name)
+    {
+        Context c = (Context) contexts.pop();
+
+        if (!c.elementName.equals(name))
+        {
+            throw new IllegalStateException("Unbalanced xml: expected to end ["
+                    + c.elementName + "]" + " but [" + name
+                    + "] was ended instead");
+        }
+
+        if (c.hasContent)
+        {
+            indentDec();
+            out.write("</");
+            out.write(c.elementName);
+            out.write(">");
+        }
+        else
+        {
+            out.write("/>");
+            --indent; // decrement the indent, but do not write the linefeed
+        }
+        openElement = false;
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/AttributeHolder.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/AttributeHolder.java
new file mode 100644
index 0000000..5aee42c
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/AttributeHolder.java
@@ -0,0 +1,34 @@
+/*
+ *  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.model;
+
+import java.util.Iterator;
+
+/**
+ * Interface for any artifact that has JSP attributes on it.
+ */
+public interface AttributeHolder
+{
+    
+    Iterator attributes();
+
+    AttributeMeta getAttribute(String name);
+
+    void addAttribute(AttributeMeta prop);
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/AttributeMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/AttributeMeta.java
new file mode 100644
index 0000000..c077b4a
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/AttributeMeta.java
@@ -0,0 +1,174 @@
+/*
+ *  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.model;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Store metadata about a attribute of a jsp tag. 
+ * <p>
+ * This metadata defines the attributes of JSP tags, among other things.
+ * 
+ * Since this is a different concept from PropertyMeta, is is left as
+ * another class (Maybe PropertyMeta must AttributeMeta but I'm not sure, since
+ * there are different concepts (a property is for jsf, an attribute is for jsp)).
+ */
+public class AttributeMeta
+{
+    private String _name;
+    private String _className;
+    private Boolean _required;
+    private String _description;
+    private String _longDescription;
+    private Boolean _rtexprvalue;
+    
+
+    public AttributeMeta()
+    {
+        
+    }
+    
+    /**
+     * Write this model out as xml.
+     */
+    public static void writeXml(XmlWriter out, AttributeMeta am)
+    {
+        out.beginElement("attribute");
+        out.writeElement("name", am._name);
+        out.writeElement("className", am._className);
+        out.writeElement("required", am._required);
+        out.writeElement("rtexprvalue", am._rtexprvalue);
+        out.writeElement("desc", am._description);
+        out.writeElement("longDesc", am._longDescription);
+        out.endElement("attribute");
+    }
+
+    /**
+     * Add digester rules to repopulate a Model instance from an xml file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/attribute";
+
+        digester.addObjectCreate(newPrefix, AttributeMeta.class);
+        digester.addSetNext(newPrefix, "addAttribute");
+
+        digester.addBeanPropertySetter(newPrefix + "/name");
+        digester.addBeanPropertySetter(newPrefix + "/className");
+        digester.addBeanPropertySetter(newPrefix + "/required");
+        digester.addBeanPropertySetter(newPrefix + "/rtexprvalue");
+        digester.addBeanPropertySetter(newPrefix + "/desc", "description");
+        digester.addBeanPropertySetter(newPrefix + "/longDesc",
+                "longDescription");
+                
+    }
+
+    /**
+     * Merge the data in the specified other property into this one, throwing an
+     * exception if there is an incompatibility.
+     */
+    public void merge(AttributeMeta other)
+    {
+        // don't merge className
+        
+        _name = ModelUtils.merge(this._name, other._name);
+        _required = ModelUtils.merge(this._required, other._required);
+        _rtexprvalue = ModelUtils.merge(this._rtexprvalue, other._rtexprvalue);
+        _description = ModelUtils.merge(this._description, other._description);
+        _longDescription = ModelUtils.merge(this._longDescription, other._longDescription);        
+    }
+    
+    
+    /**
+     * Set the name that users refer to this property by.
+     * <p>
+     * This sets the name of xml tag attributes, and the base names of generated
+     * getter/setter methods.
+     */
+    public void setName(String name)
+    {
+        _name = name;
+    }
+
+    public String getName()
+    {
+        return _name;
+    }
+
+    /**
+     * Set the fully-qualified name of the type of this property.
+     */
+    public void setClassName(String className)
+    {
+        this._className = className;
+    }
+
+    public String getClassName()
+    {
+        return _className;
+    }
+    
+    /**
+     * Specify whether this property is required, ie whether it is a syntax
+     * error for someone to use a tag for a component with this property but not
+     * explicitly provide a value for this property.
+     */
+    public void setRequired(Boolean required)
+    {
+        _required = required;
+    }
+
+    public Boolean isRequired()
+    {
+        return ModelUtils.defaultOf(_required, false);
+    }
+    
+    public void setRtexprvalue(Boolean rtexprvalue)
+    {
+        _rtexprvalue = rtexprvalue;
+    }
+
+    public Boolean isRtexprvalue()
+    {
+        return ModelUtils.defaultOf(_rtexprvalue, false);
+    }
+    
+    
+    public void setDescription(String desc)
+    {
+        _description = desc;
+    }
+
+    public String getDescription()
+    {
+        return _description;
+    }
+
+    public void setLongDescription(String desc)
+    {
+        _longDescription = desc;
+    }
+
+    public String getLongDescription()
+    {
+        return _longDescription;
+    }
+        
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ClassMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ClassMeta.java
new file mode 100644
index 0000000..1d42db6
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ClassMeta.java
@@ -0,0 +1,316 @@
+/*
+ *  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.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.lang.StringUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Base class for various metadata (model) classes.
+ * <p>
+ * This holds metadata common to all model classes that represent a JSF entity,
+ * eg a component, converter, validator, renderer. In all these cases, the class has a
+ * type, a parent and optionally a list of implemented interfaces.
+ * <p>
+ * Instances of this type are intended primarily to map to entries in generated
+ * JSP TLD files, faces-config.xml files and similar. The "class" attribute on
+ * this class contains the name of the java class that implements that entity.
+ * <p>
+ * However there are also instances of this class that represent "abstract"
+ * entities that are not directly referenced by TLD or faces-config files; they
+ * exist to represent ancestor classes of the concrete entities. 
+ * <p>
+ * The instances are created via annotations on Java classes. Therefore each
+ * ClassMeta has a "sourceClass" property that records the name of the annotated
+ * class. In simple cases, "class" and "sourceClass" are the same, ie the JSF entity
+ * <i>is</i> the class that holds the relevant annotations. But this is not true in
+ * the case of "code generation"; here the class property references the actual JSF
+ * entity (the generated class).
+ * <p>
+ * As described in the documentation for the parent attribute, the ClassMeta objects
+ * describe a java inheritance tree, but it is not quite the same as the real java
+ * inheritance hierarchy for the annotated java classes. The ClassMeta data omits
+ * any classes in the hierarchy that are not annotated, as they are not relevant
+ * for the purposes of metadata inheritance.
+ */
+public class ClassMeta
+{
+    private String _xmlElementName;
+
+    private String _className;
+    private String _parentClassName;
+    
+    private List _interfaceClassNames = new ArrayList();
+    private String _modelId;
+    private String _sourceClassName;
+    private String _sourceClassParentClassName;
+
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        digester.addBeanPropertySetter(prefix + "/modelId");
+        digester.addBeanPropertySetter(prefix + "/className");
+        digester.addBeanPropertySetter(prefix + "/parentClassName");
+        digester.addBeanPropertySetter(prefix + "/sourceClassName");
+        digester.addBeanPropertySetter(prefix + "/sourceClassParentClassName");
+        digester.addCallMethod(prefix + "/interfaces/interface",
+                "addInterfaceClassName", 1);
+        digester.addCallParam(prefix + "/interfaces/interface", 0, "name");
+    }
+
+    /**
+     * Constructor.
+     * 
+     * Param xmlElementName is the name of the xml element that is created
+     * when method writeXml is invoked.
+     */
+    protected ClassMeta(String xmlElementName)
+    {
+        _xmlElementName = xmlElementName;
+    }
+
+    /**
+     * Write the properties of this instance out as xml.
+     * <p>
+     * The name of the xml element that is created to hold the properties
+     * was specified when the constructor was called.
+     * <p>
+     * Subclasses that want to output their own properties should not
+     * override this method. Instead, they should override writeXmlSimple
+     * (and in rare cases writeXmlComplex).
+     * <p>
+     * Having two write methods (writeXmlSimple/writeXmlComplex) gives some basic
+     * control over the order in which data is written to xml, in order to make
+     * the generated xml look nice. Any properties written in writeXmlSimple will
+     * appear in the output file before properties written by writeXmlComplex. 
+     * Therefore, properties which are "easily read" should be written out in
+     * a writeXmlSimple method. Data which has large CDATA blocks, or complicated
+     * nested structure should be written out in a writeXmlComplex method so that
+     * the "simple" stuff can be easily read and is not buried in the middle of
+     * the harder-to-read output.
+     */
+    protected void writeXml(XmlWriter out)
+    {
+        out.beginElement(_xmlElementName);
+        writeXmlSimple(out);
+        writeXmlComplex(out);
+        out.endElement(_xmlElementName);
+    }
+
+    /**
+     * Write this model out as xml.
+     * <p>
+     * Subclasses that wish to write out properties as xml should override
+     * this method, call the super implementation, then call methods on the
+     * XmlWriter object to output their data.
+     */
+    protected void writeXmlSimple(XmlWriter out)
+    {
+        out.writeElement("modelId", _modelId);
+        out.writeElement("className", _className);
+        out.writeElement("parentClassName", _parentClassName);
+        out.writeElement("sourceClassName", _sourceClassName);
+        out.writeElement("sourceClassParentClassName", _sourceClassParentClassName);
+
+        // Interface data is a little complex, and could possibly be placed in the
+        // writeXmlComplex method. But except for very complicated inheritance
+        // hierarchies is is still only going to be a few lines and it logically
+        // belongs with the className/parentClassName/etc data. So it is written here
+        // along with the other "simple" data.
+        if (!_interfaceClassNames.isEmpty())
+        {
+            out.beginElement("interfaces");
+            for (Iterator i = _interfaceClassNames.iterator(); i.hasNext();)
+            {
+                String name = (String) i.next();
+                out.beginElement("interface");
+                out.writeAttr("name", name);
+                out.endElement("interface");
+            }
+            out.endElement("interfaces");
+        }
+    }
+
+    /**
+     * See documentation for writeXml and writeXmlSimple methods.
+     */
+    protected void writeXmlComplex(XmlWriter out)
+    {
+        // no complex data to write for this class.
+    }
+
+    /**
+     * Merge any inheritable data from the specified "other" instance into
+     * the metadata held by this instance.
+     */
+    protected void merge(ClassMeta other)
+    {
+        // There is nothing to merge between two ClassMeta objects;
+        // none of the properties on this class are inheritable.
+    }
+
+    /**
+     * Indicates which "group" of metadata this class belongs to.
+     * <p>
+     * Projects can inherit metadata from other projects, in which case
+     * all the ClassMeta objects end up in one big collection. But for
+     * some purposes it is necessary to iterate over the objects belonging
+     * to only one project (eg when generating components). This return
+     * value can be tested to check which "group" (project) a particular
+     * instance belongs to.
+     */
+    public String getModelId()
+    {
+        return _modelId;
+    }
+
+    public void setModelId(String modelId)
+    {
+        this._modelId = modelId;
+    }
+
+    /**
+     * The fully-qualified name of the JSF entity class, ie the class that actually
+     * implements a Component, Converter, Validator, Renderer, etc.
+     * <p>
+     * The specified class may be a hand-written one, or one created via code generation. 
+     */
+    public String getClassName()
+    {
+        return _className;
+    }
+
+    public void setClassName(String className)
+    {
+        _className = className;
+    }
+
+    /**
+     * Utility method to return just the packagename part of the className
+     * attribute.
+     */
+    public String getPackageName()
+    {
+        return StringUtils.substring(getClassName(), 0, StringUtils.lastIndexOf(getClassName(), '.'));
+    }
+
+    /**
+     * The nearest relevant (annotated) ancestor class of the class that this metadata was
+     * extracted from.
+     * <p>
+     * For example, when a class is marked as a Component class, then this will
+     * refer to the nearest ancestor class that is also marked as a Component
+     * class. Note that this is "consistent with" the actual Java class hierarchy for 
+     * annotated classes that were used to create this data, but skips java classes
+     * that were not annotated (and are therefore irrelevant for metadata purposes).
+     * <p>
+     * The value of this attribute will match the className attribute of another ClassMeta
+     * object. Following the chain of ParentClassName links (plus Interface links) gives all
+     * the ClassMeta objects needed to determine the set of metadata properties for a JSF
+     * entity.    
+     */
+    public String getParentClassName()
+    {
+        return _parentClassName;
+    }
+
+    public void setParentClassName(String className)
+    {
+        _parentClassName = className;
+    }
+
+    /**
+     * The list of relevant interface classes.
+     * <p>
+     * For example, when a class is marked as a Component class, then this will
+     * refer to the list of interfaces which that class implements that are also
+     * marked as a component.
+     */
+    public List getInterfaceClassNames()
+    {
+        return _interfaceClassNames;
+    }
+
+    public void setInterfaceClassNames(List classNames)
+    {
+        _interfaceClassNames = classNames;
+    }
+
+    public void addInterfaceClassName(String name)
+    {
+        _interfaceClassNames.add(name);
+    }
+
+    /**
+     * Return the className of the real java class from which this metadata was gathered.
+     * <p>
+     * This is mostly used for documentation. However when generating code in "template mode",
+     * this is used to locate the original class in order to find the source code to copy.
+     * It is also used for some reason in MakeComponentsMojo when determining whether to
+     * generate a class or not - this is probably wrong.
+     */
+    public String getSourceClassName()
+    {
+        return _sourceClassName;
+    }
+
+    public void setSourceClassName(String sourceClassName)
+    {
+        this._sourceClassName = sourceClassName;
+    }
+
+    /**
+     * Return the real java parent class of the class from which this metadata
+     * was gathered (see classSource property).
+     * <p>
+     * This value is usually the same as property parentClassName. However if
+     * the parent of the annotated class is not itself annotated, then this
+     * property still points to the real java parent (which will not have a
+     * ClassMeta object representing it) while property parentClass will point
+     * to the nearest superclass that does have an annotation (and does have a
+     * corresponding ClassMeta object).
+     * <p>
+     * This information is needed for code generation.
+     */
+    public void setSourceClassParentClassName(String sourceClassParentClassName)
+    {
+        this._sourceClassParentClassName = sourceClassParentClassName;
+    }
+
+    public String getSourceClassParentClassName()
+    {
+        if (_sourceClassParentClassName == null)
+        {
+            //return the parent class name instead.
+            return getParentClassName();
+        }
+        else
+        {
+            return _sourceClassParentClassName;            
+        }        
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ComponentMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ComponentMeta.java
new file mode 100644
index 0000000..74a5353
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ComponentMeta.java
@@ -0,0 +1,451 @@
+/*
+ *  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.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.lang.StringUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Store metadata about a JSF UIComponent, or some base
+ * class or interface that a UIComponent can be derived from.
+ */
+public class ComponentMeta extends ViewEntityMeta implements 
+    PropertyHolder, FacetHolder
+{
+    private String _bodyContent;
+
+    private String _type;
+    private String _family;
+    private String _rendererType;
+
+    private String _tagClass;
+    private String _tagHandler;
+    private String _tagSuperclass;
+    private Boolean _namingContainer;
+    private Boolean _children;
+    private Boolean _configExcluded;
+    private String _serialuid;
+    private String _implements;
+    
+    private Boolean _generatedComponentClass;
+    private Boolean _generatedTagClass;
+    
+    private Boolean _template;
+    
+    protected Map _facets;
+
+    /**
+     * Write an instance of this class out as xml.
+     */
+    protected void writeXmlSimple(XmlWriter out)
+    {
+        super.writeXmlSimple(out);
+
+        out.writeElement("type", _type);
+        out.writeElement("bodyContent", _bodyContent);
+        out.writeElement("family", _family);
+        out.writeElement("tagClass", _tagClass);
+        out.writeElement("tagSuperclass", _tagSuperclass);
+        out.writeElement("tagHandler", _tagHandler);
+        out.writeElement("rendererType", _rendererType);
+        out.writeElement("configExcluded", _configExcluded);
+
+        out.writeElement("serialuid", _serialuid);
+        out.writeElement("implements", _implements);
+        out.writeElement("generatedComponentClass", _generatedComponentClass);
+        out.writeElement("generatedTagClass", _generatedTagClass);
+        out.writeElement("template", _template);
+        
+        for (Iterator i = _facets.values().iterator(); i.hasNext();)
+        {
+            FacetMeta facet = (FacetMeta) i.next();
+            FacetMeta.writeXml(out, facet);
+        }
+    }
+
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/component";
+
+        digester.addObjectCreate(newPrefix, ComponentMeta.class);
+        digester.addSetNext(newPrefix, "addComponent");
+
+        ViewEntityMeta.addXmlRules(digester, newPrefix);
+
+        digester.addBeanPropertySetter(newPrefix + "/type");
+        digester.addBeanPropertySetter(newPrefix + "/bodyContent");
+        digester.addBeanPropertySetter(newPrefix + "/family");
+        digester.addBeanPropertySetter(newPrefix + "/tagClass");
+        digester.addBeanPropertySetter(newPrefix + "/tagSuperclass");
+        digester.addBeanPropertySetter(newPrefix + "/tagHandler");
+        digester.addBeanPropertySetter(newPrefix + "/rendererType");
+        digester.addBeanPropertySetter(newPrefix + "/faceletRendererType");
+        digester.addBeanPropertySetter(newPrefix + "/configExcluded");
+        digester.addBeanPropertySetter(newPrefix + "/serialuid");
+        digester.addBeanPropertySetter(newPrefix + "/implements");
+        digester.addBeanPropertySetter(newPrefix + "/generatedComponentClass");
+        digester.addBeanPropertySetter(newPrefix + "/generatedTagClass");
+        digester.addBeanPropertySetter(newPrefix + "/template");
+        
+        FacetMeta.addXmlRules(digester, newPrefix);
+    }
+
+    /**
+     * Constructor.
+     */
+    public ComponentMeta()
+    {
+        super("component");
+        _facets = new LinkedHashMap();
+    }
+
+    /**
+     * Merge the data in the specified other property into this one, throwing an
+     * exception if there is an incompatibility.
+     */
+    public void merge(ComponentMeta other)
+    {
+        _bodyContent = ModelUtils.merge(this._bodyContent, other._bodyContent);
+
+        _type = ModelUtils.merge(this._type, other._type);
+        _family = ModelUtils.merge(this._family, other._family);
+        _rendererType = ModelUtils.merge(this._rendererType,
+                other._rendererType);
+        
+        boolean inheritParentTag = false;
+        //check if the parent set a tag class
+        if (other._tagClass != null)
+        {
+            //The tagSuperclass is the tagClass of the parent
+            _tagSuperclass = ModelUtils.merge(this._tagSuperclass,
+                    other._tagClass);
+            inheritParentTag = true;
+        }
+        else
+        {
+            //The tagSuperclass is the tagSuperclass of the parent
+            _tagSuperclass = ModelUtils.merge(this._tagSuperclass,
+                    other._tagSuperclass);            
+        }
+        //_tagClass = ModelUtils.merge(this._tagClass, other._tagClass);
+        _tagHandler = ModelUtils.merge(this._tagHandler, other._tagHandler);
+        _namingContainer = ModelUtils.merge(this._namingContainer,
+                other._namingContainer);
+        _children = ModelUtils.merge(this._children, other._children);
+
+        ModelUtils.mergeProps(this, other);
+        ModelUtils.mergeFacets(this, other);
+        
+        if (inheritParentTag)
+        {
+            for (Iterator i = this.properties(); i.hasNext();)
+            {
+                PropertyMeta srcProp = (PropertyMeta) i.next();
+                PropertyMeta parentProp = other.getProperty(srcProp.getName());
+                if (parentProp != null)
+                {
+                    //There are three possible behaviors:
+                    //1. The property is defined on the child again and
+                    //   the property was already on the tag hierarchy, so
+                    //   inheritedTag must be set to TRUE.
+                    //2. The property is defined on the child again and
+                    //   it is necessary to write again on the generated
+                    //   tag, so the annotation looks like
+                    //   "@JSFProperty inheritedTag=false"
+                    //   This condition must remain as FALSE
+                    //3. The property is set by the user as true, but there
+                    //   was not defined previously on the hierarchy, so
+                    //   this condition must be as is (TRUE) 
+                    //   (skipped on parentProp != null).
+                    if (srcProp.isLocalInheritedTag() == null ||
+                            srcProp.isInheritedTag().booleanValue())
+                    {
+                        srcProp.setInheritedTag(Boolean.TRUE);
+                    }
+                }
+            }
+            _propertyTagList = null;
+        }
+    }
+
+    public void setBodyContent(String bodyContent)
+    {
+        this._bodyContent = bodyContent;
+    }
+
+    public String getBodyContent()
+    {
+        return _bodyContent;
+    }
+
+    /**
+     * Sets the JSF component type for this component.
+     */
+    public void setType(String componentType)
+    {
+        _type = componentType;
+    }
+
+    public String getType()
+    {
+        return _type;
+    }
+
+    /**
+     * Sets the JSF component family for this component.
+     */
+    public void setFamily(String componentFamily)
+    {
+        _family = componentFamily;
+    }
+
+    public String getFamily()
+    {
+        return _family;
+    }
+
+    /**
+     * Sets the renderer type for this component.
+     */
+    public void setRendererType(String rendererType)
+    {
+        _rendererType = rendererType;
+    }
+
+    public String getRendererType()
+    {
+        return _rendererType;
+    }
+
+    /**
+     * Sets the JSP tag handler class for this component.
+     */
+    public void setTagClass(String tagClass)
+    {
+        _tagClass = tagClass;
+    }
+
+    public String getTagClass()
+    {
+        return _tagClass;
+    }
+
+    /**
+     * Sets the JSP tag handler superclass for this component.
+     */
+    public void setTagSuperclass(String tagSuperclass)
+    {
+        _tagSuperclass = tagSuperclass;
+    }
+
+    public String getTagSuperclass()
+    {
+        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.
+     */
+    public void setTagHandler(String tagHandler)
+    {
+        _tagHandler = tagHandler;
+    }
+
+    public String getTagHandler()
+    {
+        return _tagHandler;
+    }
+
+    /**
+     * Specifies whether this component is a "naming container", ie whether it
+     * adds its own clientId as a prefix onto the clientId of its child
+     * components.
+     */
+    public void setNamingContainer(Boolean namingContainer)
+    {
+        _namingContainer = namingContainer;
+    }
+
+    public Boolean getNamingContainer()
+    {
+        return ModelUtils.defaultOf(_namingContainer, false);
+    }
+
+    public void setConfigExcluded(Boolean configExcluded)
+    {
+        _configExcluded = configExcluded;
+    }
+
+    public Boolean isConfigExcluded()
+    {
+        return ModelUtils.defaultOf(_configExcluded,false);
+    }
+    
+    public void setSerialuid(String serialuid)
+    {
+        _serialuid = serialuid;
+    }
+
+    public String getSerialuid()
+    {
+        return _serialuid;
+    }
+    
+
+    public void setImplements(String implementsValue)
+    {
+        _implements = implementsValue;
+    }
+
+    public String getImplements()
+    {
+        return _implements;
+    }
+
+    public void setGeneratedComponentClass(Boolean generatedComponentClass)
+    {
+        _generatedComponentClass = generatedComponentClass;
+    }
+
+    public Boolean isGeneratedComponentClass()
+    {
+        return ModelUtils.defaultOf(_generatedComponentClass,false);
+    }
+
+    public void setGeneratedTagClass(Boolean generatedTagClass)
+    {
+        _generatedTagClass = generatedTagClass;
+    }
+
+    public Boolean isGeneratedTagClass()
+    {
+        return ModelUtils.defaultOf(_generatedTagClass,false);
+    }
+    
+    public void setTemplate(Boolean template)
+    {
+        _template = template;
+    }
+
+    public Boolean isTemplate()
+    {
+        return ModelUtils.defaultOf(_template,false);
+    }
+
+    /**
+     * Specifies if the component supports child components.
+     */
+    public void setChildren(Boolean children)
+    {
+        _children = children;
+    }
+
+    public Boolean hasChildren()
+    {
+        return ModelUtils.defaultOf(_children, true);
+    }
+
+    public void addFacet(FacetMeta prop)
+    {
+        _facets.put(prop.getName(), prop);
+    }
+
+    public Iterator facets()
+    {
+        return _facets.values().iterator();
+    }
+
+    public FacetMeta getFacet(String name)
+    {
+        return (FacetMeta) _facets.get(name);
+    }
+            
+    //THIS METHODS ARE USED FOR VELOCITY TO GET DATA AND GENERATE CLASSES
+    
+    public Collection getFacetList()
+    {
+        return _facets.values();
+    }
+    
+    private List _propertyTagList = null; 
+    
+    public Collection getPropertyTagList()
+    {
+        if (_propertyTagList == null)
+        {
+            _propertyTagList = new ArrayList();
+            for (Iterator it = getPropertyList().iterator(); it.hasNext();)
+            {
+                PropertyMeta prop = (PropertyMeta) it.next();
+                if (!prop.isTagExcluded().booleanValue() &&
+                        !prop.isInheritedTag().booleanValue())
+                {
+                    _propertyTagList.add(prop);
+                }
+            }
+            
+        }
+        return _propertyTagList;
+    }
+    
+    private List _propertyComponentList = null; 
+    
+    public Collection getPropertyComponentList()
+    {
+        if (_propertyComponentList == null)
+        {
+            _propertyComponentList = new ArrayList();
+            for (Iterator it = getPropertyList().iterator(); it.hasNext();)
+            {
+                PropertyMeta prop = (PropertyMeta) it.next();
+                if (!prop.isInherited().booleanValue() && prop.isGenerated().booleanValue())
+                {
+                    _propertyComponentList.add(prop);
+                }
+            }
+            
+        }
+        return _propertyComponentList;
+    }
+
+    /**
+     * Returns the package part of the tag class
+     * 
+     * @return
+     */
+    public String getTagPackage()
+    {
+        return StringUtils.substring(getTagClass(), 0, StringUtils.lastIndexOf(getTagClass(), '.'));
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java
new file mode 100644
index 0000000..ced3f82
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java
@@ -0,0 +1,298 @@
+/*
+ *  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.model;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Store metadata about a class that is either a JSF Converter, or some base
+ * class or interface that a Converter can be derived from.
+ * <p>
+ * A converter can be used in three ways:
+ * <ul>
+ * <li>instantiated via a tag,
+ * <li>referenced via its id,
+ * <li>implicitly used via its forClass property
+ * </ul>
+ */
+public class ConverterMeta extends ViewEntityMeta implements PropertyHolder
+{
+    private String _converterId;
+    private int _converterClassModifiers;
+    
+    //Some converters has its own tag class, so it's necessary to
+    //add some properties for this cases (f:convertNumber or f:convertDateTime)
+    private String _bodyContent;
+    private String _tagClass;
+    private String _tagSuperclass;
+    private String _serialuidtag;
+    
+    private Boolean _generatedTagClass;
+    private Boolean _configExcluded;
+
+    /**
+     * Write an instance of this class out as xml.
+     */
+    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("serialuidtag", _serialuidtag);
+        out.writeElement("generatedTagClass", _generatedTagClass);
+        out.writeElement("configExcluded", _configExcluded);
+    }
+
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/converter";
+
+        digester.addObjectCreate(newPrefix, ConverterMeta.class);
+        digester.addSetNext(newPrefix, "addConverter");
+
+        ViewEntityMeta.addXmlRules(digester, newPrefix);
+
+        digester.addBeanPropertySetter(newPrefix + "/converterId");
+        digester.addBeanPropertySetter(newPrefix + "/bodyContent");
+        digester.addBeanPropertySetter(newPrefix + "/tagClass");
+        digester.addBeanPropertySetter(newPrefix + "/tagSuperclass");
+        digester.addBeanPropertySetter(newPrefix + "/serialuidtag");
+        digester.addBeanPropertySetter(newPrefix + "/generatedTagClass");
+        digester.addBeanPropertySetter(newPrefix + "/configExcluded");
+    }
+    
+    public ConverterMeta()
+    {
+        super("converter");
+    }
+
+    /**
+     * Merge the data in the specified other property into this one, throwing an
+     * exception if there is an incompatibility.
+     * 
+     * Not used right now since theorically there is very few inheritance
+     * on converters
+     * 
+     */
+    public void merge(ConverterMeta other)
+    {
+        super.merge(other);
+        _bodyContent = ModelUtils.merge(this._bodyContent, other._bodyContent);
+
+        boolean inheritParentTag = false;
+        //check if the parent set a tag class
+        if (other._tagClass != null)
+        {
+            //The tagSuperclass is the tagClass of the parent
+            _tagSuperclass = ModelUtils.merge(this._tagSuperclass,
+                    other._tagClass);
+            inheritParentTag = true;
+        }
+        else
+        {
+            //The tagSuperclass is the tagSuperclass of the parent
+            _tagSuperclass = ModelUtils.merge(this._tagSuperclass,
+                    other._tagSuperclass);            
+        }
+
+        _converterId = ModelUtils.merge(this._converterId, other._converterId);
+        
+        // TODO: _converterClassMOdifiers
+        
+        if (inheritParentTag)
+        {
+            for (Iterator i = this.properties(); i.hasNext();)
+            {
+                PropertyMeta srcProp = (PropertyMeta) i.next();
+                PropertyMeta parentProp = other.getProperty(srcProp.getName());
+                if (parentProp != null)
+                {
+                    if (!srcProp.isTagExcluded().booleanValue())
+                    {
+                        //There are three possible behaviors:
+                        //1. The property is defined on the child again and
+                        //   the property was already on the tag hierarchy, so
+                        //   inheritedTag must be set to TRUE.
+                        //2. The property is defined on the child again and
+                        //   it is necessary to write again on the generated
+                        //   tag, so the annotation looks like
+                        //   "@JSFProperty inheritedTag=false"
+                        //   This condition must remain as FALSE
+                        //3. The property is set by the user as true, but there
+                        //   was not defined previously on the hierarchy, so
+                        //   this condition must be as is (TRUE) 
+                        //   (skipped on parentProp != null).
+                        if (srcProp.isLocalInheritedTag() == null ||
+                                srcProp.isInheritedTag().booleanValue())
+                        {
+                            srcProp.setInheritedTag(Boolean.TRUE);
+                        }
+                    }
+                }
+            }
+            _propertyTagList = null;
+        }        
+
+    }
+
+    /**
+     * Sets the converter identifer for this component.
+     */
+    public void setConverterId(String converterId)
+    {
+        _converterId = converterId;
+    }
+
+    public String getConverterId()
+    {
+        return _converterId;
+    }
+
+    /**
+     * Adds a Java Language class modifier to the converter class.
+     * <p>
+     * TODO: what is this for????
+     */
+    public void addConverterClassModifier(int modifier)
+    {
+        _converterClassModifiers |= modifier;
+    }
+
+    /**
+     * Returns the Java Language class modifiers for the converter class. By
+     * default, these modifiers include Modifier.PUBLIC.
+     * 
+     * @return the Java Language class modifiers for the converter class
+     */
+    public int getConverterClassModifiers()
+    {
+        int modifiers = _converterClassModifiers;
+
+        if (!Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers)
+                && !Modifier.isPublic(modifiers))
+        {
+            modifiers |= Modifier.PUBLIC;
+        }
+
+        return modifiers;
+    }
+
+    public void setBodyContent(String bodyContent)
+    {
+        this._bodyContent = bodyContent;
+    }
+
+    public String getBodyContent()
+    {
+        return _bodyContent;
+    }
+
+    /**
+     * Sets the JSP tag handler class for this component.
+     */
+    public void setTagClass(String tagClass)
+    {
+        _tagClass = tagClass;
+    }
+
+    public String getTagClass()
+    {
+        return _tagClass;
+    }
+    
+    /**
+     * Sets the JSP tag handler superclass for this component.
+     */
+    public void setTagSuperclass(String tagSuperclass)
+    {
+        _tagSuperclass = tagSuperclass;
+    }
+
+    public String getTagSuperclass()
+    {
+        return _tagSuperclass;
+    }
+    
+    public void setSerialuidtag(String serialuidtag)
+    {
+        _serialuidtag = serialuidtag;
+    }
+
+    public String getSerialuidtag()
+    {
+        return _serialuidtag;
+    }
+    
+    public void setGeneratedTagClass(Boolean generatedTagClass)
+    {
+        _generatedTagClass = generatedTagClass;
+    }
+
+    public Boolean isGeneratedTagClass()
+    {
+        return ModelUtils.defaultOf(_generatedTagClass,false);
+    }
+
+    public void setConfigExcluded(Boolean configExcluded)
+    {
+        _configExcluded = configExcluded;
+    }
+
+    public Boolean isConfigExcluded()
+    {
+        return ModelUtils.defaultOf(_configExcluded,false);
+    }    
+
+    //THIS METHODS ARE USED FOR VELOCITY TO GET DATA AND GENERATE CLASSES
+    
+    private List _propertyTagList = null; 
+    
+    public Collection getPropertyTagList()
+    {
+        if (_propertyTagList == null)
+        {
+            _propertyTagList = new ArrayList();
+            for (Iterator it = getPropertyList().iterator(); it.hasNext();)
+            {
+                PropertyMeta prop = (PropertyMeta) it.next();
+                if (!prop.isTagExcluded().booleanValue() &&
+                        !prop.isInheritedTag().booleanValue())
+                {
+                    _propertyTagList.add(prop);
+                }
+            }
+            
+        }
+        return _propertyTagList;
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/FacetHolder.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/FacetHolder.java
new file mode 100644
index 0000000..a12d350
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/FacetHolder.java
@@ -0,0 +1,34 @@
+/*
+ *  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.model;
+
+import java.util.Iterator;
+
+/**
+ * Interface for any artifact that has JSF facets on it.
+ */
+public interface FacetHolder
+{
+    
+    Iterator facets();
+
+    FacetMeta getFacet(String name);
+
+    void addFacet(FacetMeta prop);
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/FacetMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/FacetMeta.java
new file mode 100644
index 0000000..7bb7f27
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/FacetMeta.java
@@ -0,0 +1,195 @@
+/*
+ *  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.model;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * FacetBean is a Java representation of the faces-config component or
+ * renderer facet XML element.
+ */
+public class FacetMeta
+{
+    private String _longDescription;
+    private String _description;
+    private String _name;
+    private Boolean _required;
+    
+    private Boolean _inherited; //Define if this facet is inherited from parent component
+    private Boolean _generated; //Define if this facet should be generated
+
+    public FacetMeta()
+    {
+        
+    }
+    
+    public FacetMeta(FacetMeta pm)
+    {
+        _name = pm._name;
+        _required = pm._required;
+        _description = pm._description;
+        _longDescription = pm._longDescription;
+        _inherited = pm._inherited;
+    }
+    
+    /**
+     * Write this model out as xml.
+     */
+    public static void writeXml(XmlWriter out, FacetMeta am)
+    {
+        out.beginElement("facet");
+        out.writeElement("name", am._name);
+        out.writeElement("required", am._required);
+        out.writeElement("desc", am._description);
+        out.writeElement("longDesc", am._longDescription);
+        out.writeElement("inherited", am._inherited);
+        out.endElement("facet");
+    }
+
+    /**
+     * Add digester rules to repopulate a Model instance from an xml file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/facet";
+
+        digester.addObjectCreate(newPrefix, FacetMeta.class);
+        digester.addSetNext(newPrefix, "addFacet");
+
+        digester.addBeanPropertySetter(newPrefix + "/name");
+        digester.addBeanPropertySetter(newPrefix + "/required");
+        digester.addBeanPropertySetter(newPrefix + "/desc", "description");
+        digester.addBeanPropertySetter(newPrefix + "/longDesc",
+                "longDescription");
+        digester.addBeanPropertySetter(newPrefix + "/inherited", "inherited");        
+    }
+
+    /**
+     * Merge the data in the specified other property into this one, throwing an
+     * exception if there is an incompatibility.
+     */
+    public void merge(FacetMeta other)
+    {
+        
+        _name = ModelUtils.merge(this._name, other._name);
+        _required = ModelUtils.merge(this._required, other._required);
+        _description = ModelUtils.merge(this._description, other._description);
+        _longDescription = ModelUtils.merge(this._longDescription, other._longDescription);        
+    }
+    
+    
+    
+    /**
+     * Sets the facet name for this facet.
+     *
+     * @param facetName  the facet name
+     */
+    public void setName(String name)
+    {
+        _name = name;
+    }
+    
+    /**
+     * Returns the facet name for this facet.
+     *
+     * @return  the facet name
+     */
+    public String getName()
+    {
+        return _name;
+    }
+    
+    /**
+     * Sets the description of this property.
+     *
+     * @param description  the property description
+     */
+    public void setDescription(String description)
+    {
+        _description = description;
+    }
+
+    /**
+     * Returns the description of this property.
+     *
+     * @return  the property description
+     */
+    public String getDescription()
+    {
+        return _description;
+    }
+
+    /**
+     * Sets the required flag of this facet.
+     *
+     * @param required  the facet required flag
+     */
+    public void setRequired(Boolean required)
+    {
+        _required = required;
+    }
+
+    /**
+     * Returns required flag of this facet.
+     *
+     * @return  the facet required flag
+     */
+    public Boolean isRequired()
+    {
+        return ModelUtils.defaultOf(_required,false);
+    }
+    
+    public void setLongDescription(String desc)
+    {
+        _longDescription = desc;
+    }
+
+    public String getLongDescription()
+    {
+        return _longDescription;
+    }
+    
+    public void setInherited(Boolean inherited)
+    {
+        _inherited = inherited;
+    }
+
+    public Boolean isInherited()
+    {
+        return ModelUtils.defaultOf(_inherited, false);
+    }
+    
+    public void setGenerated(Boolean generated)
+    {
+        _generated = generated;
+    }
+
+    /**
+     * Indicates if the property should be generated
+     * or not.
+     * 
+     * @return
+     */
+    public Boolean isGenerated()
+    {
+        return ModelUtils.defaultOf(_generated, false);
+    }
+    
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/MethodSignatureMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/MethodSignatureMeta.java
new file mode 100644
index 0000000..8818a6f
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/MethodSignatureMeta.java
@@ -0,0 +1,124 @@
+/*
+ *  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.model;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * MethodSignatureMeta is a Java representation of the faces-config component
+ * property-extension method-signature XML element.
+ */
+public class MethodSignatureMeta extends Object
+{
+    /**
+     * Creates a new MethodSignatureBean.
+     */
+    public MethodSignatureMeta()
+    {
+        _parameterTypes = new LinkedList();
+    }
+    
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/methodBindingSignature";
+        digester.addObjectCreate(newPrefix , MethodSignatureMeta.class);
+        digester.addBeanPropertySetter(newPrefix +"/returnType", "returnType");
+        digester.addCallMethod(newPrefix +"/parameterType","addParameterType", 1);
+        digester.addCallParam(newPrefix +"/parameterType", 0);
+        digester.addSetNext(newPrefix ,"setMethodBindingSignature", MethodSignatureMeta.class.getName());
+        
+    }
+    
+    public static void writeXml(XmlWriter out, MethodSignatureMeta pm)
+    {
+        out.beginElement("methodBindingSignature");
+        out.writeElement("returnType", pm._returnType);
+        
+        for (Iterator i = pm._parameterTypes.iterator(); i.hasNext();)
+        {
+            String param = (String) i.next();
+            out.writeElement("parameterType", param);
+        }
+        
+        out.endElement("methodBindingSignature");
+    }
+
+    /**
+     * Adds a new parameter type to this method signature.
+     *
+     * @param parameterType  the parameter type
+     */
+    public void addParameterType(String parameterType)
+    {
+        _parameterTypes.add(parameterType);
+    }
+
+    /**
+     * Returns the list of parameter types as an array.
+     *
+     * @return  the parameter type list
+     */
+    public String[] getParameterTypes()
+    {
+        return (String[]) _parameterTypes.toArray(new String[0]);
+    }
+    
+    public String getParameterTypesAsString()
+    {
+        String[] params = this.getParameterTypes();
+        StringBuilder resp = new StringBuilder(); 
+        for (int i = 0; i < params.length; i++)
+        {
+          if (i > 0)
+          {
+            resp.append(", ");
+          }
+          resp.append(params[i]);
+        }
+        return resp.toString();
+    }
+
+    /**
+     * Sets the return type of this method signature.
+     *
+     * @param returnType  the method signature return type
+     */
+    public void setReturnType(String returnType)
+    {
+        _returnType = returnType;
+    }
+
+    /**
+     * Returns the return type of this method signature.
+     *
+     * @return  the method signature return type
+     */
+    public String getReturnType()
+    {
+        return _returnType;
+    }
+
+    private String _returnType;
+    private List _parameterTypes;
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/Model.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/Model.java
new file mode 100644
index 0000000..b6c560d
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/Model.java
@@ -0,0 +1,348 @@
+/*
+ *  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.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.logging.Logger;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Stores info about all of the jsf artifacts in the system being processed.
+ */
+public class Model
+{
+    static private final Logger _log = Logger.getLogger(Model.class.getName());
+
+    private List _components = new ArrayList(100);
+    private List _converters = new ArrayList(100);
+    private List _validators = new ArrayList(100);
+    private List _renderKits = new ArrayList(100);
+    private List _tags = new ArrayList(100);    
+
+    private Map _componentsByClass = new TreeMap();
+    private Map _convertersByClass = new TreeMap();
+    private Map _validatorsByClass = new TreeMap();
+    private Map _renderKitsById = new TreeMap();
+    private Map _tagsByClass =  new TreeMap();
+    
+    private String _modelId;
+
+    /**
+     * Write this model out as xml.
+     * <p>
+     * Having a hand-coded method like this is not very elegant; it would be
+     * better to do this via some library like Betwixt. However I'm not very
+     * familiar with such libs, so hand-coding is quicker for now.
+     */
+    public static void writeXml(XmlWriter out, Model model)
+    {
+        out.beginElement("model");
+        out.writeElement("modelId", model._modelId);
+
+        for (Iterator i = model._components.iterator(); i.hasNext();)
+        {
+            ComponentMeta c = (ComponentMeta) i.next();
+            c.writeXml(out);
+        }
+
+        for (Iterator i = model._converters.iterator(); i.hasNext();)
+        {
+            ConverterMeta c = (ConverterMeta) i.next();
+            c.writeXml(out);
+        }
+
+        for (Iterator i = model._validators.iterator(); i.hasNext();)
+        {
+            ValidatorMeta c = (ValidatorMeta) i.next();
+            c.writeXml(out);
+        }
+        
+        for (Iterator i = model._renderKits.iterator(); i.hasNext();)
+        {
+            RenderKitMeta c = (RenderKitMeta) i.next();
+            RenderKitMeta.writeXml(out, c);
+        }
+        
+        for (Iterator i = model._tags.iterator(); i.hasNext();)
+        {
+            TagMeta c = (TagMeta) i.next();
+            c.writeXml(out);
+        }        
+
+        out.endElement("model");
+    }
+
+    /**
+     * Add digester rules to repopulate a Model instance from an xml file.
+     * <p>
+     * Having a hand-coded method like this is not very elegant; it would be
+     * better to do this via some library like Betwixt. However I'm not very
+     * familiar with such libs, so hand-coding is quicker for now.
+     */
+    public static void addXmlRules(Digester digester)
+    {
+        String prefix = "model";
+
+        digester.addObjectCreate(prefix, Model.class);
+        digester.addBeanPropertySetter(prefix + "/modelId");
+        ComponentMeta.addXmlRules(digester, prefix);
+        ConverterMeta.addXmlRules(digester, prefix);
+        ValidatorMeta.addXmlRules(digester, prefix);
+        RenderKitMeta.addXmlRules(digester, prefix);
+        TagMeta.addXmlRules(digester, prefix);
+    }
+    
+    /**
+     * Adds all components from the other model to this model, because
+     * only this info is necessary from construct a full model of 
+     * components and build correctly faces-config.xml, .tld, and
+     * component and tag classes.
+     * 
+     * @param other
+     */
+    public void merge(Model other)
+    {
+        for (Iterator it = other.getComponents().iterator(); it.hasNext();)
+        {
+            ComponentMeta component = (ComponentMeta) it.next();
+            //If the component is present, the actual takes precedence.
+            if (this.findComponentByClassName(component.getClassName())== null)
+            {
+                this.addComponent(component);
+            }
+        }
+        
+        for (Iterator it = other.getConverters().iterator(); it.hasNext();)
+        {
+            ConverterMeta converter = (ConverterMeta) it.next();
+            
+            if (this.findConverterByClassName(converter.getClassName())== null)
+            {
+                this.addConverter(converter);
+            }
+        }
+        
+        for (Iterator it = other.getValidators().iterator(); it.hasNext();)
+        {
+            ValidatorMeta validator = (ValidatorMeta) it.next();
+            
+            if (this.findValidatorByClassName(validator.getClassName())== null)
+            {
+                this.addValidator(validator);
+            }
+        }
+        
+        for (Iterator it = other.getTags().iterator(); it.hasNext();)
+        {
+            TagMeta validator = (TagMeta) it.next();
+            
+            if (this.findTagByClassName(validator.getClassName())== null)
+            {
+                this.addTag(validator);
+            }
+        }        
+    }
+
+    /**
+     * Adds a component to this faces config document.
+     * 
+     * @param component
+     *            the component to add
+     */
+    public void addComponent(ComponentMeta component)
+    {
+        _components.add(component);
+        _componentsByClass.put(component.getClassName(), component);
+    }
+
+    /**
+     * Returns all components
+     */
+    public List getComponents()
+    {
+        return _components;
+    }
+
+    /**
+     * Returns an iterator for all components.
+     */
+    public Iterator components()
+    {
+        return _components.iterator();
+    }
+
+    public ComponentMeta findComponentByClassName(String className)
+    {
+        return (ComponentMeta) _componentsByClass.get(className);
+    }
+
+    /**
+     * Holds info about a JSF Converter definition
+     */
+    public void addConverter(ConverterMeta converter)
+    {
+        _converters.add(converter);
+        _convertersByClass.put(converter.getClassName(), converter);
+    }
+
+    /**
+     * Returns all converters
+     */
+    public List getConverters()
+    {
+        return _converters;
+    }
+
+    /**
+     * Returns an iterator for all converters
+     */
+    public Iterator converters()
+    {
+        return _converters.iterator();
+    }
+
+    public ConverterMeta findConverterByClassName(String className)
+    {
+        return (ConverterMeta) _convertersByClass.get(className);
+    }
+
+    /**
+     * Holds info about a JSF Converter definition
+     */
+    public void addValidator(ValidatorMeta validator)
+    {
+        _validators.add(validator);
+        _validatorsByClass.put(validator.getClassName(), validator);
+    }
+
+    /**
+     * Returns all validators
+     */
+    public List getValidators()
+    {
+        return _validators;
+    }
+
+    /**
+     * Returns an iterator for all validators
+     */
+    public Iterator validators()
+    {
+        return _validators.iterator();
+    }
+
+    public ValidatorMeta findValidatorByClassName(String className)
+    {
+        return (ValidatorMeta) _validatorsByClass.get(className);
+    }
+
+    /**
+     * Adds a render kit to this faces config document.
+     * 
+     * @param renderKit
+     *            the render kit to add
+     */
+    public void addRenderKit(RenderKitMeta renderKit)
+    {
+        _renderKits.add(renderKit);
+        _renderKitsById.put(renderKit.getRenderKitId(), renderKit);
+    }
+
+    public List getRenderKits()
+    {
+        return _renderKits;
+    }
+
+    /**
+     * Returns an iterator for all render kits in this faces config.
+     * 
+     * @return the render kit iterator
+     */
+    public Iterator renderKits()
+    {
+        return _renderKits.iterator();
+    }
+
+    /**
+     * Returns the render kit for this render kit id.
+     * 
+     * @param renderKitId
+     *            the render kit id to find
+     */
+    public RenderKitMeta findRenderKitById(String id)
+    {
+        return (RenderKitMeta) _renderKitsById.get(id);
+    }
+    
+    /**
+     * Adds a tag to this faces config document.
+     * 
+     * @param tag
+     *            the tag to add
+     */
+    public void addTag(TagMeta tag)
+    {
+        _tags.add(tag);
+        _tagsByClass.put(tag.getClassName(), tag);
+    }
+
+    /**
+     * Returns all tags
+     */
+    public List getTags()
+    {
+        return _tags;
+    }
+
+    /**
+     * Returns an iterator for all tags.
+     */
+    public Iterator tags()
+    {
+        return _tags.iterator();
+    }
+
+    public TagMeta findTagByClassName(String className)
+    {
+        return (TagMeta) _tagsByClass.get(className);
+    }
+    
+
+    public void setModelId(String modelId)
+    {
+        this._modelId = modelId;
+    }
+
+    /**
+     * Obtain a value that indicate from where this model
+     * comes from.
+     * 
+     * @return
+     */
+    public String getModelId()
+    {
+        return _modelId;
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ModelUtils.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ModelUtils.java
new file mode 100644
index 0000000..30f3c10
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ModelUtils.java
@@ -0,0 +1,128 @@
+/*
+ *  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.model;
+
+import java.util.Iterator;
+
+/**
+ * Simple static helper methods.
+ */
+public class ModelUtils
+{
+    /**
+     * Inherit setting only if current one is empty.
+     */
+    public static String merge(String curr, String inherited)
+    {
+        if (curr != null)
+        {
+            return curr;
+        }
+        return inherited;
+    }
+    
+    /**
+     * Inherit setting only if current one is empty.
+     */
+    public static Object merge(Object curr, Object inherited)
+    {
+        if (curr != null)
+        {
+            return curr;
+        }
+        return inherited;
+    }    
+    
+    /**
+     * Inherit setting only if current one is empty.
+     */
+    public static Boolean merge(Boolean curr, Boolean inherited)
+    {
+        if (curr != null)
+        {
+            return curr;
+        }
+        return inherited;
+    }
+
+    /**
+     * Return a default value if a boolean property is null.
+     */
+    public static Boolean defaultOf(Boolean val, boolean dflt)
+    {
+        if (val != null)
+        {
+            return val;
+        }
+        else
+        {
+            return Boolean.valueOf(dflt);
+        }
+    }
+
+    /**
+     * Given two JSF artifacts that can have associated user-settable properties,
+     * merge all the properties one one into the other.
+     * <p>
+     * The dst object is expected to be a "child" of the src object. Any data on dst
+     * therefore overrides stuff on src, but otherwise everything on src gets copied
+     * to dst.
+     */
+    public static void mergeProps(PropertyHolder dst, PropertyHolder src)
+    {
+        for (Iterator i = src.properties(); i.hasNext();)
+        {
+            PropertyMeta srcProp = (PropertyMeta) i.next();
+            PropertyMeta dstProp = dst.getProperty(srcProp.getName());
+            if (dstProp == null)
+            {
+                // Just copy the whole property unaltered
+                dstProp = new PropertyMeta(srcProp);
+                dstProp.setInherited(Boolean.TRUE);
+                dst.addProperty(dstProp);
+            }
+            else
+            {
+                // merge the two property objects together
+                dstProp.merge(srcProp);
+            }
+        }
+    }
+    
+    public static void mergeFacets(FacetHolder dst, FacetHolder src)
+    {
+        for (Iterator i = src.facets(); i.hasNext();)
+        {
+            FacetMeta srcProp = (FacetMeta) i.next();
+            FacetMeta dstProp = dst.getFacet(srcProp.getName());
+            if (dstProp == null)
+            {
+                // Just copy the whole property unaltered
+                dstProp = new FacetMeta(srcProp);
+                dstProp.setInherited(Boolean.TRUE);
+                dst.addFacet(dstProp);
+            }
+            else
+            {
+                // merge the two property objects together
+                dstProp.merge(srcProp);
+            }
+        }
+    }    
+}
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/PropertyHolder.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/PropertyHolder.java
new file mode 100644
index 0000000..bc73237
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/PropertyHolder.java
@@ -0,0 +1,36 @@
+/*
+ *  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.model;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Interface for any artifact that has JSF properties on it.
+ */
+public interface PropertyHolder
+{
+    Iterator properties();
+
+    PropertyMeta getProperty(String name);
+
+    void addProperty(PropertyMeta prop);
+    
+    Map getProperties();
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/PropertyMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/PropertyMeta.java
new file mode 100644
index 0000000..c0667d8
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/PropertyMeta.java
@@ -0,0 +1,525 @@
+/*
+ *  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.model;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Store metadata about a bean property of a component, converter or other JSF
+ * artifact.
+ * <p>
+ * This metadata defines the attributes of JSP tags, among other things.
+ */
+public class PropertyMeta
+{
+    private String _name;
+    private String _className;
+    private String _jspName;
+    private String _fieldName;    
+    private Boolean _required;
+    private Boolean _literalOnly;
+    private Boolean _transient;
+    private Boolean _stateHolder;
+    private String _description;
+    private String _longDescription;
+    private String   _defaultValue;
+    private MethodSignatureMeta _signature;
+    
+    private Boolean _inherited; //Define if this property is inherited from parent component
+    private Boolean _inheritedTag; //Define if this property is inherited from tag component
+    private Boolean _tagExcluded; //Define if this property is excluded from tag and tld
+    
+    private Boolean _generated;
+    
+    private String _localMethodScope;
+    private Boolean _localMethod; //generate method that returns local value without evaluate EL
+    private String _setMethodScope;
+    private Boolean _setMethod; //Generate method to define if is set a value or not
+    
+    private Boolean _rtexprvalue;
+
+    public PropertyMeta()
+    {
+        
+    }
+    
+    public PropertyMeta(PropertyMeta pm)
+    {
+        _name = pm._name;
+        _className = pm._className;
+        _jspName = pm._jspName;
+        _fieldName = pm._fieldName;    
+        _required = pm._required;
+        _literalOnly = pm._literalOnly;
+        _transient = pm._transient;
+        _stateHolder = pm._stateHolder;
+        _description = pm._description;
+        _longDescription = pm._longDescription;
+        _defaultValue = pm._defaultValue;
+        _signature = pm._signature;
+        
+        _inherited = pm._inherited;
+        _inheritedTag = pm._inheritedTag;
+        _tagExcluded = pm._tagExcluded;
+        
+        _generated = pm._generated;
+        _localMethodScope = pm._localMethodScope;
+        _localMethod = pm._localMethod;
+        _setMethodScope = pm._setMethodScope;
+        _setMethod = pm._setMethod;
+        _rtexprvalue = pm._rtexprvalue;
+        
+    }
+    
+    /**
+     * Write this model out as xml.
+     */
+    public static void writeXml(XmlWriter out, PropertyMeta pm)
+    {
+        out.beginElement("property");
+        out.writeElement("name", pm._name);
+        if (pm._jspName != null)
+        {
+            out.writeElement("jspName", pm._jspName);
+        }
+        if (pm._fieldName != null)
+        {
+            out.writeElement("fieldName", pm._fieldName);
+        }
+        out.writeElement("className", pm._className);
+        out.writeElement("required", pm._required);
+        out.writeElement("literalOnly", pm._literalOnly);
+        out.writeElement("transient", pm._transient);
+        out.writeElement("stateHolder", pm._stateHolder);
+        out.writeElement("desc", pm._description);
+        out.writeElement("longDesc", pm._longDescription);
+        out.writeElement("defaultValue", pm._defaultValue);
+        if (pm._signature != null)
+        {
+            MethodSignatureMeta.writeXml(out, pm._signature);
+        }
+        out.writeElement("inherited", pm._inherited);
+        out.writeElement("inheritedTag", pm._inheritedTag);
+        out.writeElement("tagExcluded", pm._tagExcluded);
+        out.writeElement("generated",pm._generated);
+        out.writeElement("localMethodScope", pm._localMethodScope);
+        out.writeElement("localMethod", pm._localMethod);
+        out.writeElement("setMethodScope", pm._setMethodScope);
+        out.writeElement("setMethod", pm._setMethod);
+        out.writeElement("rtexprvalue", pm._rtexprvalue);
+        out.endElement("property");
+    }
+
+    /**
+     * Add digester rules to repopulate a Model instance from an xml file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/property";
+
+        digester.addObjectCreate(newPrefix, PropertyMeta.class);
+        digester.addSetNext(newPrefix, "addProperty");
+
+        digester.addBeanPropertySetter(newPrefix + "/name");
+        digester.addBeanPropertySetter(newPrefix + "/jspName");
+        digester.addBeanPropertySetter(newPrefix + "/fieldName");
+        digester.addBeanPropertySetter(newPrefix + "/className");
+        digester.addBeanPropertySetter(newPrefix + "/required");
+        digester.addBeanPropertySetter(newPrefix + "/literalOnly");
+        digester.addBeanPropertySetter(newPrefix + "/transient");
+        digester.addBeanPropertySetter(newPrefix + "/stateHolder");
+        digester.addBeanPropertySetter(newPrefix + "/desc", "description");
+        digester.addBeanPropertySetter(newPrefix + "/longDesc",
+                "longDescription");
+        digester.addBeanPropertySetter(newPrefix + "/defaultValue", "defaultValue");
+        digester.addBeanPropertySetter(newPrefix + "/inherited", "inherited");
+        digester.addBeanPropertySetter(newPrefix + "/inheritedTag", "inheritedTag");
+        digester.addBeanPropertySetter(newPrefix + "/tagExcluded", "tagExcluded");
+        digester.addBeanPropertySetter(newPrefix + "/generated", "generated");
+        digester.addBeanPropertySetter(newPrefix + "/localMethodScope", "localMethodScope");
+        digester.addBeanPropertySetter(newPrefix + "/localMethod", "localMethod");
+        digester.addBeanPropertySetter(newPrefix + "/setMethodScope", "setMethodScope");
+        digester.addBeanPropertySetter(newPrefix + "/setMethod", "setMethod");
+        digester.addBeanPropertySetter(newPrefix + "/rtexprvalue", "rtexprvalue");
+        MethodSignatureMeta.addXmlRules(digester, newPrefix);
+        
+    }
+
+    /**
+     * Merge the data in the specified other property into this one, throwing an
+     * exception if there is an incompatibility.
+     */
+    public void merge(PropertyMeta other)
+    {
+        // Merge className does not harm, since you cannot
+        //use polymorphism on a jsf component.  
+        _className = ModelUtils.merge(this._className, other._className);
+        
+        _name = ModelUtils.merge(this._name, other._name);
+        _jspName = ModelUtils.merge(this._jspName, other._jspName);
+        _fieldName = ModelUtils.merge(this._fieldName, other._fieldName);
+        _required = ModelUtils.merge(this._required, other._required);
+        _literalOnly = ModelUtils.merge(this._literalOnly, other._literalOnly);
+        _transient = ModelUtils.merge(this._transient, other._transient);
+        _stateHolder = ModelUtils.merge(this._stateHolder, other._stateHolder);
+        _description = ModelUtils.merge(this._description, other._description);
+        _longDescription = ModelUtils.merge(this._longDescription, other._longDescription);
+        _defaultValue = ModelUtils.merge(this._defaultValue, other._defaultValue);
+        _signature = (MethodSignatureMeta) ModelUtils.merge(this._signature, other._signature);
+        _generated = ModelUtils.merge(this._generated, other._generated);
+        _localMethod = ModelUtils.merge(this._localMethod, other._localMethod);
+        _localMethodScope = ModelUtils.merge(this._localMethodScope, other._localMethodScope);
+        _setMethodScope = ModelUtils.merge(this._setMethodScope, other._setMethodScope);
+        _setMethod = ModelUtils.merge(this._setMethod, other._setMethod);
+        _tagExcluded = ModelUtils.merge(this._tagExcluded, other._tagExcluded);
+        _rtexprvalue = ModelUtils.merge(this._rtexprvalue, other._rtexprvalue);
+    }
+
+    /**
+     * Set the name that users refer to this property by.
+     * <p>
+     * This sets the name of xml tag attributes, and the base names of generated
+     * getter/setter methods.
+     */
+    public void setName(String name)
+    {
+        _name = name;
+    }
+
+    public String getName()
+    {
+        return _name;
+    }
+
+    /**
+     * Set the fully-qualified name of the type of this property.
+     */
+    public void setClassName(String className)
+    {
+        this._className = className;
+    }
+
+    public String getClassName()
+    {
+        return _className;
+    }
+
+    /**
+     * Specify whether this property is transient or not.
+     * <p>
+     * Transient properties are not saved in the view state and are not restored
+     * during the "restore view" phase.
+     */
+    public void setTransient(Boolean state)
+    {
+        _transient = state;
+    }
+
+    public Boolean isTransient()
+    {
+        return ModelUtils.defaultOf(_transient, false);
+    }
+
+    /**
+     * Specify whether this property is required, ie whether it is a syntax
+     * error for someone to use a tag for a component with this property but not
+     * explicitly provide a value for this property.
+     */
+    public void setRequired(Boolean required)
+    {
+        _required = required;
+    }
+
+    public Boolean isRequired()
+    {
+        return ModelUtils.defaultOf(_required, false);
+    }
+
+    /**
+     * Specify whether this property accepts only literal (constant) values, or
+     * whether this property can be mapped to an EL expression.
+     */
+    public void setLiteralOnly(Boolean literalOnly)
+    {
+        _literalOnly = literalOnly;
+    }
+
+    public Boolean isLiteralOnly()
+    {
+        return ModelUtils.defaultOf(_literalOnly, false);
+    }
+
+    public void setDescription(String desc)
+    {
+        _description = desc;
+    }
+
+    public String getDescription()
+    {
+        return _description;
+    }
+
+    public void setLongDescription(String desc)
+    {
+        _longDescription = desc;
+    }
+
+    public String getLongDescription()
+    {
+        return _longDescription;
+    }
+    
+    /**
+     * Sets the default value of this attribute.
+     *
+     * @param defaultValue  the attribute default value
+     */
+    public void setDefaultValue(String defaultValue)
+    {
+      _defaultValue = defaultValue;
+    }
+
+    /**
+     * Returns the default value of this attribute.
+     *
+     * @return  the attribute default value
+     */
+    public String getDefaultValue()
+    {
+      return _defaultValue;
+    }
+    
+    /**
+     * Sets the JSP name of this property.
+     *
+     * @param jspName  the JSP property name
+     */
+    public void setJspName(String jspName)
+    {
+      _jspName = jspName;
+    }
+
+    /**
+     * Returns the JSP name of this property.
+     *
+     * @return  the JSP property name
+     */
+    public String getJspName()
+    {
+      if (_jspName == null)
+      {
+        return getName();
+      }
+
+      return _jspName;
+    }
+
+    /**
+     * Sets the field name of this property, when not generating Trinidad components
+     *
+     * @param fieldName  the field property name
+     */
+    public void setFieldName(String fieldName)
+    {
+      _fieldName = fieldName;
+    }
+
+    /**
+     * Returns the field name of this property, when not generating Trinidad components
+     *
+     * @return  the field property name
+     */
+    public String getFieldName()
+    {
+      if (_fieldName == null)
+      {
+        return "_"+getName();
+      }
+
+      return _fieldName;
+    }
+            
+    /**
+     * Sets the method binding signature of this property.
+     *
+     * @param signature  the method binding signature of this property
+     */
+    public void setMethodBindingSignature(
+      MethodSignatureMeta signature)
+    {
+      _signature = signature;
+    }
+
+    /**
+     * Returns the method binding signature of this property.
+     *
+     * @return the method binding signature of this property
+     */
+    public MethodSignatureMeta getMethodBindingSignature()
+    {
+      return _signature;
+    }
+    
+    public void setInherited(Boolean inherited)
+    {
+        _inherited = inherited;
+    }
+
+    public Boolean isInherited()
+    {
+        return ModelUtils.defaultOf(_inherited, false);
+    }
+
+    public void setInheritedTag(Boolean inheritedTag)
+    {
+        _inheritedTag = inheritedTag;
+    }
+
+    /**
+     * Returns true if this property was inherited from an ancestor component
+     * which has no associated tag class.
+     * <p>
+     * When a tag class is generated for <i>this</i> component, then the tag
+     * class will need to define a setter method to handle this property.
+     * <p>
+     * However properties which are inherited from an ancestor component that
+     * does have a tag class will not need 
+     * @param inheritedTag
+     */
+    public Boolean isInheritedTag()
+    {
+        return ModelUtils.defaultOf(_inheritedTag, false);
+    }
+    
+    /**
+     * 
+     */
+    public Boolean isLocalInheritedTag()
+    {
+        return _inheritedTag;
+    }
+    
+    public void setTagExcluded(Boolean tagExcluded)
+    {
+        _tagExcluded = tagExcluded;
+    }
+
+    public Boolean isTagExcluded()
+    {
+        return ModelUtils.defaultOf(_tagExcluded, false);
+    }
+    
+    public void setGenerated(Boolean generated)
+    {
+        _generated = generated;
+    }
+
+    /**
+     * Indicates if the property should be generated
+     * or not.
+     * 
+     * @return
+     */
+    public Boolean isGenerated()
+    {
+        return ModelUtils.defaultOf(_generated, false);
+    }
+
+    public void setStateHolder(Boolean stateHolder)
+    {
+        _stateHolder = stateHolder;
+    }
+
+    public Boolean isStateHolder()
+    {
+        return ModelUtils.defaultOf(_stateHolder, false);
+    }
+
+    public void setLocalMethodScope(String localMethodScope)
+    {
+        _localMethodScope = localMethodScope;
+    }
+
+    public String getLocalMethodScope()
+    {
+        return _localMethodScope == null ? "protected" : _localMethodScope;
+    }
+
+    public void setLocalMethod(Boolean localMethod)
+    {
+        _localMethod = localMethod;
+    }
+
+    public Boolean isLocalMethod()
+    {
+        return ModelUtils.defaultOf(_localMethod,false);
+    }
+
+    public void setSetMethodScope(String setMethodScope)
+    {
+        _setMethodScope = setMethodScope;
+    }
+
+    public String getSetMethodScope()
+    {
+        return _setMethodScope == null ? "protected" : _setMethodScope;
+    }
+
+    public void setSetMethod(Boolean setMethod)
+    {
+        _setMethod = setMethod;
+    }
+    
+    public void setRtexprvalue(Boolean rtexprvalue)
+    {
+        _rtexprvalue = rtexprvalue;
+    }
+
+    public Boolean isRtexprvalue()
+    {
+        return _rtexprvalue;
+    }
+    
+
+    public Boolean isSetMethod()
+    {
+        return ModelUtils.defaultOf(_setMethod,false);
+    }
+
+    /**
+     * Returns true if this property is a method binding.
+     * <p>
+     * TODO: what is this for?
+     */
+    public boolean isMethodBinding()
+    {
+        return ("javax.faces.el.MethodBinding".equals(getClassName()));
+    }
+
+    /**
+     * Returns true if this property is a method binding.
+     * <p>
+     * TODO: what is this for?
+     */
+    public boolean isMethodExpression()
+    {
+        return ("javax.el.MethodExpression".equals(getClassName()));
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/RenderKitMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/RenderKitMeta.java
new file mode 100644
index 0000000..408af1c
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/RenderKitMeta.java
@@ -0,0 +1,182 @@
+/*
+ *  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.model;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Store metadata about a JSF RenderKit.
+ */
+public class RenderKitMeta
+{
+    private String _className;
+
+    private String _renderKitId = "";
+    private Map _renderers;
+
+    /**
+     * Write an instance of this class out as xml.
+     */
+    public static void writeXml(XmlWriter out, RenderKitMeta rkm)
+    {
+        out.beginElement("renderKit");
+                
+        out.writeElement("renderKitId", rkm._renderKitId);
+        out.writeElement("className", rkm._className);
+        
+        for (Iterator it = rkm._renderers.values().iterator();it.hasNext();)
+        {
+            RendererMeta rm = (RendererMeta) it.next();
+            rm.writeXml(out);  
+        }
+        
+        out.endElement("renderKit");        
+    }
+    
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/renderKit";
+
+        digester.addObjectCreate(newPrefix, RenderKitMeta.class);
+        digester.addSetNext(newPrefix, "addRenderKit");
+
+        ClassMeta.addXmlRules(digester, newPrefix);
+
+        digester.addBeanPropertySetter(newPrefix + "/renderKitId");
+        digester.addBeanPropertySetter(newPrefix + "/className");
+        
+        RendererMeta.addXmlRules(digester, newPrefix);
+    }
+
+
+    /**
+     * Creates a new RenderKitBean.
+     */
+    public RenderKitMeta()
+    {
+        _renderers = new TreeMap();
+    }
+
+    /**
+     * The name of the class that this metadata applies to.
+     */
+    public String getClassName()
+    {
+        return _className;
+    }
+
+    public void setClassName(String className)
+    {
+        _className = className;
+    }
+
+    /**
+     * Sets the render kit id for this component.
+     * 
+     * @param renderKitId
+     *            the render kit id
+     */
+    public void setRenderKitId(String renderKitId)
+    {
+        _renderKitId = renderKitId;
+    }
+
+    /**
+     * Returns the render kit id type for this component.
+     * 
+     * @return the render kit id
+     */
+    public String getRenderKitId()
+    {
+        return _renderKitId;
+    }
+
+    /**
+     * Adds a renderer to this render kit.
+     * 
+     * @param renderer
+     *            the renderer to add
+     */
+    public void addRenderer(RendererMeta renderer)
+    {
+        String componentFamily = renderer.getComponentFamily();
+        String rendererType = renderer.getRendererType();
+        String compositeKey = componentFamily + "|" + rendererType;
+        _renderers.put(compositeKey, renderer);
+    }
+
+    /**
+     * Returns the renderer for this component family and renderer type.
+     * 
+     * @param componentFamily
+     *            the component family
+     * @param rendererType
+     *            the renderer type
+     */
+    public RendererMeta findRenderer(String componentFamily,
+            String rendererType)
+    {
+        String compositeKey = componentFamily + "|" + rendererType;
+        return (RendererMeta) _renderers.get(compositeKey);
+    }
+
+    /**
+     * Returns true if this render kit has any renderers.
+     * 
+     * @return true if this render kit has any renderers, false otherwise
+     */
+    public boolean hasRenderers()
+    {
+        return !_renderers.isEmpty();
+    }
+
+    /**
+     * Returns an iterator for all renderers in this render kit.
+     * 
+     * @return the renderer iterator
+     */
+    public Iterator renderers()
+    {
+        return _renderers.values().iterator();
+    }
+    
+    public Collection getRenderers()
+    {
+        return _renderers.values();
+    }
+
+    void addAllRenderers(RenderKitMeta renderKit)
+    {
+        for (Iterator i = renderKit._renderers.values().iterator(); i.hasNext();)
+        {
+            // use addRenderer to establish owner
+            addRenderer((RendererMeta) i.next());
+        }
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/RendererMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/RendererMeta.java
new file mode 100644
index 0000000..754b546
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/RendererMeta.java
@@ -0,0 +1,136 @@
+/*
+ *  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.model;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+
+/**
+ * Store metadata about a class that is either a JSF Renderer, or some base
+ * class or interface that a Renderer can be derived from.
+ */
+public class RendererMeta extends ClassMeta
+{
+    private String _description;
+    private String _componentFamily;
+    private String _rendererType;
+
+    /**
+     * Write an instance of this class out as xml.
+     */
+    protected void writeXmlSimple(XmlWriter out)
+    {
+        super.writeXmlSimple(out);
+        
+        out.writeElement("componentFamily", _componentFamily);
+        out.writeElement("rendererType", _rendererType);
+        out.writeElement("description", _description);
+    }
+    
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/renderer";
+
+        digester.addObjectCreate(newPrefix, RendererMeta.class);
+        digester.addSetNext(newPrefix, "addRenderer");
+
+        ClassMeta.addXmlRules(digester, newPrefix);
+
+        digester.addBeanPropertySetter(newPrefix + "/componentFamily");
+        digester.addBeanPropertySetter(newPrefix + "/rendererType");
+        digester.addBeanPropertySetter(newPrefix + "/description");
+    }
+    
+    /**
+     * Creates a new RendererBean.
+     */
+    public RendererMeta()
+    {
+        super("renderer");
+    }    
+
+    /**
+     * Sets the component family for this component.
+     * 
+     * @param componentFamily
+     *            the component family
+     */
+    public void setComponentFamily(String componentFamily)
+    {
+        _componentFamily = componentFamily;
+    }
+
+    /**
+     * Returns the component family for this component.
+     * 
+     * @return the component family
+     */
+    public String getComponentFamily()
+    {
+        return _componentFamily;
+    }
+
+    /**
+     * Sets the renderer type for this component.
+     * 
+     * @param rendererType
+     *            the renderer type
+     */
+    public void setRendererType(String rendererType)
+    {
+        _rendererType = rendererType;
+    }
+
+    /**
+     * Returns the renderer type for this component.
+     * 
+     * @return the renderer type
+     */
+    public String getRendererType()
+    {
+        return _rendererType;
+    }
+
+    /**
+     * Sets the description of this attribute.
+     * 
+     * @param description
+     *            the attribute description
+     */
+    public void setDescription(String description)
+    {
+        _description = description;
+    }
+
+    /**
+     * Returns the description of this attribute.
+     * 
+     * @return the attribute description
+     */
+    public String getDescription()
+    {
+        return _description;
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/TagMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/TagMeta.java
new file mode 100644
index 0000000..ea5338d
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/TagMeta.java
@@ -0,0 +1,254 @@
+/*
+ *  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.model;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Represents metadata about a class that is just a pure JSF Tag class,
+ * with no corresponding JSF component, validator or converter.
+ * <p>
+ * There are not very many pure tag classes, but there are a few. One
+ * example is the f:attribute tag from the JSF core specification, which
+ * exists solely to store an entry into the attributes map of some other
+ * component when the view is first created.
+ * <p>
+ * Another example is the f:converter tag, which creates a corresponding
+ * converter component by id, and stores it into the view. The tag 
+ * doesn't correspond to any particular converter class, so there is
+ * no converter class whose annotations can be used to describe this
+ * generic tag. Note that specific converters can also have their own
+ * dedicated tags (eg f:convertDateTime) in which case the TLD entry
+ * is generated using metadata from the converter class.
+ * <p>
+ * Another case when this is needed is where there are multiple tags that
+ * correspond to a single component class. For example, in the core
+ * implementation both f:outputText and f:verbatim are implemented with
+ * the UIOutputText component. In this case, the component is used to
+ * generate one TLD entry (the "primary" tag) but TLD entries for the
+ * "secondary" tag must be triggered in another way.
+ * <p>
+ * In the above cases, the tag class itself can be annotated with this
+ * annotation. During TLD file generation, an appropriate entry is then
+ * added.
+ * <p>
+ * An alternative is to omit this entry, and simply write the TLD
+ * entries for these few classes by hand in the "base" file that gets
+ * included into the generated one.
+ */
+public class TagMeta extends ClassMeta implements AttributeHolder
+{
+    private String _name;
+    private String _bodyContent;
+    private String _description;
+    private String _longDescription;
+    private String _tagHandler;
+
+    protected Map _attributes;
+    
+    /**
+     * Write an instance of this class out as xml.
+     */
+    protected void writeXmlSimple(XmlWriter out)
+    {
+        super.writeXmlSimple(out);
+
+        out.writeElement("name", _name);
+        out.writeElement("bodyContent", _bodyContent);
+        out.writeElement("desc", _description);
+        out.writeElement("longDesc", _longDescription);
+        out.writeElement("tagHandler", _tagHandler);
+
+        for (Iterator i = _attributes.values().iterator(); i.hasNext();)
+        {
+            AttributeMeta prop = (AttributeMeta) i.next();
+            AttributeMeta.writeXml(out, prop);
+        }
+    }
+
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/tag";
+
+        digester.addObjectCreate(newPrefix, TagMeta.class);
+        digester.addSetNext(newPrefix, "addTag");
+
+        ClassMeta.addXmlRules(digester, newPrefix);
+        digester.addBeanPropertySetter(newPrefix + "/name", "name");
+        digester.addBeanPropertySetter(newPrefix + "/bodyContent", "bodyContent");
+        digester.addBeanPropertySetter(newPrefix + "/desc", "description");
+        digester.addBeanPropertySetter(newPrefix + "/longDesc",
+                "longDescription");
+        digester.addBeanPropertySetter(newPrefix + "/tagHandler");
+        
+        AttributeMeta.addXmlRules(digester, newPrefix);
+    }
+
+    /**
+     * Constructor.
+     */
+    public TagMeta()
+    {
+        super("tag");
+        _attributes = new LinkedHashMap();
+    }
+
+    /**
+     * Merge the data in the specified other property into this one, throwing an
+     * exception if there is an incompatibility.
+     */
+    public void merge(TagMeta other)
+    {
+        _name = ModelUtils.merge(this._name, other._name);
+        _description = ModelUtils.merge(this._description, other._description);
+        _longDescription = ModelUtils.merge(this._longDescription,
+                other._longDescription);
+        _bodyContent = ModelUtils.merge(this._bodyContent, other._bodyContent);
+        _tagHandler = ModelUtils.merge(this._tagHandler, other._tagHandler);
+        //TODO: Merge attributes
+    }
+    
+    /**
+     * Sets the brief description of this property.
+     * <p>
+     * This description is used in tooltips, etc.
+     */
+    public void setDescription(String description)
+    {
+        _description = description;
+    }
+
+    public String getDescription()
+    {
+        return _description;
+    }
+
+    /**
+     * Sets the long description of this property.
+     */
+    public void setLongDescription(String longDescription)
+    {
+        _longDescription = longDescription;
+    }
+
+    public String getLongDescription()
+    {
+        return _longDescription;
+    }
+        
+    public void setBodyContent(String bodyContent)
+    {
+        this._bodyContent = bodyContent;
+    }
+
+    public String getBodyContent()
+    {
+        return _bodyContent;
+    }
+    
+    /**
+     * Sets the name that the user will refer to instances of this component by.
+     * <p>
+     * In JSP tags, this value will be used as the JSP tag name.
+     * <p>
+     * This property is optional; if not set then this Model instance represents
+     * a base class that components can be derived from, but which cannot itself
+     * be instantiated as a component.
+     */
+    public void setName(String name)
+    {
+        _name = name;
+    }
+
+    public String getName()
+    {
+        return _name;
+    }
+    
+    /**
+     * 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.
+     */
+    public void setTagHandler(String tagHandler)
+    {
+        _tagHandler = tagHandler;
+    }
+
+    public String getTagHandler()
+    {
+        return _tagHandler;
+    }
+    
+    /**
+     * Adds a property to this component.
+     */
+    public void addAttribute(AttributeMeta attribute)
+    {
+        _attributes.put(attribute.getName(), attribute);
+    }
+
+    public AttributeMeta getAttribute(String attributeName)
+    {
+        return (AttributeMeta) _attributes.get(attributeName);
+    }
+
+    /**
+     * Number of properties for this component
+     */
+    public int attributesSize()
+    {
+        return _attributes.size();
+    }
+
+    /**
+     * Returns true if this component has any properties.
+     */
+    public boolean hasAttributes()
+    {
+        return _attributes.size() > 0;
+    }
+
+    /**
+     * Returns an iterator for all properties
+     */
+    public Iterator attributes()
+    {
+        return _attributes.values().iterator();
+    }
+    
+    //THIS METHODS ARE USED FOR VELOCITY TO GET DATA AND GENERATE CLASSES
+    
+    public Collection getAttributeList()
+    {
+        return _attributes.values();
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ValidatorMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ValidatorMeta.java
new file mode 100644
index 0000000..2dc3a5a
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ValidatorMeta.java
@@ -0,0 +1,336 @@
+/*
+ *  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.model;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+/**
+ * Store metadata about a class that is either a JSF Validator, or some base
+ * class or interface that a Validator can be derived from.
+ */
+public class ValidatorMeta extends ViewEntityMeta implements PropertyHolder
+{
+    private String _validatorId;
+    private int _validatorClassModifiers;
+    
+    private String _bodyContent;
+    private String _tagClass;
+    private String _tagSuperclass;
+    private String _serialuidtag;
+    
+    private Boolean _generatedComponentClass;
+    private Boolean _generatedTagClass;
+    private Boolean _configExcluded;
+
+    /**
+     * Write an instance of this class out as xml.
+     */
+    protected void writeXmlSimple(XmlWriter out)
+    {
+        super.writeXmlSimple(out);
+
+        out.writeElement("validatorId", _validatorId);
+        out.writeElement("bodyContent", _bodyContent);
+        out.writeElement("tagClass", _tagClass);
+        out.writeElement("tagSuperclass", _tagSuperclass);
+        out.writeElement("serialuidtag", _serialuidtag);
+        out.writeElement("generatedComponentClass", _generatedComponentClass);
+        out.writeElement("generatedTagClass", _generatedTagClass);
+        out.writeElement("configExcluded", _configExcluded);
+    }
+
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        String newPrefix = prefix + "/validator";
+
+        digester.addObjectCreate(newPrefix, ValidatorMeta.class);
+        digester.addSetNext(newPrefix, "addValidator");
+
+        ViewEntityMeta.addXmlRules(digester, newPrefix);
+
+        digester.addBeanPropertySetter(newPrefix + "/validatorId");
+        digester.addBeanPropertySetter(newPrefix + "/bodyContent");
+        digester.addBeanPropertySetter(newPrefix + "/tagClass");
+        digester.addBeanPropertySetter(newPrefix + "/tagSuperclass");
+        digester.addBeanPropertySetter(newPrefix + "/serialuidtag");
+        digester.addBeanPropertySetter(newPrefix + "/generatedComponentClass");
+        digester.addBeanPropertySetter(newPrefix + "/generatedTagClass");
+        digester.addBeanPropertySetter(newPrefix + "/configExcluded");
+    }
+    
+    public ValidatorMeta()
+    {
+        super("validator");
+    }
+
+    /**
+     * Merge the data in the specified other property into this one, throwing an
+     * exception if there is an incompatibility.
+     * 
+     * Not used right now since theorically there is very few inheritance
+     * on converters
+     * 
+     */
+    public void merge(ValidatorMeta 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;
+        if (other._tagClass != null)
+        {
+            //The tagSuperclass is the tagClass of the parent
+            _tagSuperclass = ModelUtils.merge(this._tagSuperclass,
+                    other._tagClass);
+            inheritParentTag = true;
+        }
+        else
+        {
+            //The tagSuperclass is the tagSuperclass of the parent
+            _tagSuperclass = ModelUtils.merge(this._tagSuperclass,
+                    other._tagSuperclass);            
+        }
+
+        
+        _validatorId = ModelUtils.merge(this._validatorId, other._validatorId);
+
+        // TODO: _validatorClassMOdifiers
+        
+        if (inheritParentTag)
+        {
+            for (Iterator i = this.properties(); i.hasNext();)
+            {
+                PropertyMeta srcProp = (PropertyMeta) i.next();
+                PropertyMeta parentProp = other.getProperty(srcProp.getName());
+                if (parentProp != null)
+                {
+                    //There are three possible behaviors:
+                    //1. The property is defined on the child again and
+                    //   the property was already on the tag hierarchy, so
+                    //   inheritedTag must be set to TRUE.
+                    //2. The property is defined on the child again and
+                    //   it is necessary to write again on the generated
+                    //   tag, so the annotation looks like
+                    //   "@JSFProperty inheritedTag=false"
+                    //   This condition must remain as FALSE
+                    //3. The property is set by the user as true, but there
+                    //   was not defined previously on the hierarchy, so
+                    //   this condition must be as is (TRUE) 
+                    //   (skipped on parentProp != null).
+                    if (srcProp.isLocalInheritedTag() == null ||
+                            srcProp.isInheritedTag().booleanValue())
+                    {
+                        srcProp.setInheritedTag(Boolean.TRUE);
+                    }
+                }
+            }
+            _propertyTagList = null;
+        }        
+    }
+
+    /**
+     * Sets the validator identifer for this component.
+     */
+    public void setValidatorId(String validatorId)
+    {
+        _validatorId = validatorId;
+    }
+
+    public String getValidatorId()
+    {
+        return _validatorId;
+    }
+
+    /**
+     * Adds a Java Language class modifier to the validator class.
+     * <p>
+     * TODO: what is this for?
+     */
+    public void addValidatorClassModifier(int modifier)
+    {
+        _validatorClassModifiers |= modifier;
+    }
+
+    /**
+     * Returns the Java Language class modifiers for the validator class. By
+     * default, these modifiers include Modifier.PUBLIC.
+     * 
+     * @return the Java Language class modifiers for the validator class
+     */
+    public int getValidatorClassModifiers()
+    {
+        int modifiers = _validatorClassModifiers;
+
+        if (!Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers)
+                && !Modifier.isPublic(modifiers))
+        {
+            modifiers |= Modifier.PUBLIC;
+        }
+
+        return modifiers;
+    }
+    
+    public void setBodyContent(String bodyContent)
+    {
+        this._bodyContent = bodyContent;
+    }
+
+    public String getBodyContent()
+    {
+        return _bodyContent;
+    }
+
+    /**
+     * Sets the JSP tag handler class for this component.
+     */
+    public void setTagClass(String tagClass)
+    {
+        _tagClass = tagClass;
+    }
+
+    public String getTagClass()
+    {
+        return _tagClass;
+    }
+
+    /**
+     * Sets the JSP tag handler superclass for this component.
+     */
+    public void setTagSuperclass(String tagSuperclass)
+    {
+        _tagSuperclass = tagSuperclass;
+    }
+
+    public String getTagSuperclass()
+    {
+        return _tagSuperclass;
+    }
+    
+    public void setSerialuidtag(String serialuidtag)
+    {
+        _serialuidtag = serialuidtag;
+    }
+
+    public String getSerialuidtag()
+    {
+        return _serialuidtag;
+    }
+    
+    public void setGeneratedComponentClass(Boolean generatedComponentClass)
+    {
+        _generatedComponentClass = generatedComponentClass;
+    }
+
+    public Boolean isGeneratedComponentClass()
+    {
+        return ModelUtils.defaultOf(_generatedComponentClass,false);
+    }
+
+    public void setGeneratedTagClass(Boolean generatedTagClass)
+    {
+        _generatedTagClass = generatedTagClass;
+    }
+
+    public Boolean isGeneratedTagClass()
+    {
+        return ModelUtils.defaultOf(_generatedTagClass,false);
+    }
+    
+    public void setConfigExcluded(Boolean configExcluded)
+    {
+        _configExcluded = configExcluded;
+    }
+
+    public Boolean isConfigExcluded()
+    {
+        return ModelUtils.defaultOf(_configExcluded,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()
+    {
+        if (_propertyTagList == null)
+        {
+            _propertyTagList = new ArrayList();
+            for (Iterator it = getPropertyList().iterator(); it.hasNext();)
+            {
+                PropertyMeta prop = (PropertyMeta) it.next();
+                if (!prop.isTagExcluded().booleanValue() &&
+                        !prop.isInheritedTag().booleanValue())
+                {
+                    _propertyTagList.add(prop);
+                }
+            }
+            
+        }
+        return _propertyTagList;
+    }
+
+    private List _propertyValidatorList = null; 
+
+    public Collection getPropertyValidatorList()
+    {
+        if (_propertyValidatorList == null)
+        {
+            _propertyValidatorList = new ArrayList();
+            for (Iterator it = getPropertyList().iterator(); it.hasNext();)
+            {
+                PropertyMeta prop = (PropertyMeta) it.next();
+                if (!prop.isInherited().booleanValue() && prop.isGenerated().booleanValue())
+                {
+                    _propertyValidatorList.add(prop);
+                }
+            }
+            
+        }
+        return _propertyValidatorList;
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ViewEntityMeta.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ViewEntityMeta.java
new file mode 100644
index 0000000..0980858
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ViewEntityMeta.java
@@ -0,0 +1,197 @@
+/*
+ *  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.model;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.digester.Digester;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.io.XmlWriter;
+
+
+/**
+ * Base class for metadata about any class whose instances can be used in a
+ * JSF view.
+ * <p>
+ * This means Components, Converters, Validators.
+ */
+public abstract class ViewEntityMeta extends ClassMeta implements PropertyHolder
+{
+    private String _name;
+    private String _description;
+    private String _longDescription;
+    private Map _properties = new LinkedHashMap();
+
+    /**
+     * Add digester rules to repopulate an instance of this type from an xml
+     * file.
+     */
+    public static void addXmlRules(Digester digester, String prefix)
+    {
+        ClassMeta.addXmlRules(digester, prefix);
+
+        digester.addBeanPropertySetter(prefix + "/name");
+        digester.addBeanPropertySetter(prefix + "/desc", "description");
+        digester.addBeanPropertySetter(prefix + "/longDesc",
+                "longDescription");
+        PropertyMeta.addXmlRules(digester, prefix);
+    }
+
+    /**
+     * Constructor.
+     */
+    public ViewEntityMeta(String xmlElementName)
+    {
+        super(xmlElementName);
+    }
+
+    /**
+     * Implement callback method to write out the "simple" properties of
+     * this class as xml.
+     */
+    protected void writeXmlSimple(XmlWriter out)
+    {
+        super.writeXmlSimple(out);
+
+        out.writeElement("name", _name);
+    }
+
+    /**
+     * Implement callback method to write out the "complex" properties of
+     * this class as xml.
+     */
+    protected void writeXmlComplex(XmlWriter out)
+    {
+        super.writeXmlComplex(out);
+        out.writeElement("desc", _description);
+        out.writeElement("longDesc", _longDescription);
+        for (Iterator i = _properties.values().iterator(); i.hasNext();)
+        {
+            PropertyMeta prop = (PropertyMeta) i.next();
+            PropertyMeta.writeXml(out, prop);
+        }
+    }
+
+    protected void merge(ViewEntityMeta other)
+    {
+        super.merge(other);
+        // name cannot be merged
+        _description = ModelUtils.merge(this._description, other._description);
+        _longDescription = ModelUtils.merge(this._longDescription,
+                other._longDescription);
+        ModelUtils.mergeProps(this, other);
+    }
+
+
+    /**
+     * Sets the name that the user will refer to instances of this component by.
+     * <p>
+     * In JSP tags, this value will be used as the JSP tag name.
+     * <p>
+     * This property is optional; if not set then this Model instance represents
+     * a base class that components can be derived from, but which cannot itself
+     * be instantiated as a component.
+     */
+    public void setName(String name)
+    {
+        _name = name;
+    }
+
+    public String getName()
+    {
+        return _name;
+    }
+
+    /**
+     * Sets the brief description of this property.
+     * <p>
+     * This description is used in tooltips, etc.
+     */
+    public void setDescription(String description)
+    {
+        _description = description;
+    }
+
+    public String getDescription()
+    {
+        return _description;
+    }
+
+    /**
+     * Sets the long description of this property.
+     */
+    public void setLongDescription(String longDescription)
+    {
+        _longDescription = longDescription;
+    }
+
+    public String getLongDescription()
+    {
+        return _longDescription;
+    }
+
+    /**
+     * Adds a property to this component.
+     */
+    public void addProperty(PropertyMeta property)
+    {
+        _properties.put(property.getName(), property);
+    }
+
+    public PropertyMeta getProperty(String propertyName)
+    {
+        return (PropertyMeta) _properties.get(propertyName);
+    }
+
+    /**
+     * Number of properties for this component
+     */
+    public int propertiesSize()
+    {
+        return _properties.size();
+    }
+
+    /**
+     * Returns true if this component has any properties.
+     */
+    public boolean hasProperties()
+    {
+        return _properties.size() > 0;
+    }
+
+    public Map getProperties()
+    {
+        return _properties;
+    }
+
+    public Collection getPropertyList()
+    {
+        return _properties.values();
+    }
+
+    /**
+     * Returns an iterator for all properties
+     */
+    public Iterator properties()
+    {
+        return _properties.values().iterator();
+    }
+}
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java
new file mode 100644
index 0000000..587e19a
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java
@@ -0,0 +1,1734 @@
+/*
+ *  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.qdox;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.ModelBuilder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.AttributeMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ClassMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.MethodSignatureMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RenderKitMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RendererMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.TagMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
+import org.codehaus.plexus.components.io.fileselectors.FileInfo;
+import org.codehaus.plexus.components.io.fileselectors.FileSelector;
+import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
+
+import com.thoughtworks.qdox.JavaDocBuilder;
+import com.thoughtworks.qdox.model.AbstractJavaEntity;
+import com.thoughtworks.qdox.model.Annotation;
+import com.thoughtworks.qdox.model.DocletTag;
+import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaField;
+import com.thoughtworks.qdox.model.JavaMethod;
+import com.thoughtworks.qdox.model.Type;
+import com.thoughtworks.qdox.parser.structs.AnnoDef;
+
+/**
+ * An implementation of the ModelBuilder interface that uses the Qdox java
+ * source-parsing library to scan a list of specified source directories for
+ * java files.
+ * <p>
+ * The java source files found can use either java15 annotations or doclet
+ * annotations to indicate what data should be added to the Model.
+ */
+public class QdoxModelBuilder implements ModelBuilder
+{
+    private final Log log = LogFactory.getLog(QdoxModelBuilder.class);
+
+    private static final String DOC_CONVERTER = "JSFConverter";
+    private static final String DOC_VALIDATOR = "JSFValidator";
+    private static final String DOC_COMPONENT = "JSFComponent";
+    private static final String DOC_RENDERER = "JSFRenderer";
+    private static final String DOC_RENDERKIT = "JSFRenderKit";
+    private static final String DOC_RENDERERS = "JSFRenderers";
+
+    private static final String DOC_PROPERTY = "JSFProperty";
+    private static final String DOC_FACET = "JSFFacet";   
+    
+    //This property is used in special cases where properties 
+    //does not have methods defined on component class, like binding
+    //in jsf 1.1 (in 1.2 has component counterpart). In fact, all
+    //properties must be defined with JSFProperty
+    private static final String DOC_JSP_PROPERTY = "JSFJspProperty";
+    private static final String DOC_JSP_PROPERTIES = "JSFJspProperties";
+    
+    private static final String DOC_TAG = "JSFJspTag";
+    private static final String DOC_JSP_ATTRIBUTE = "JSFJspAttribute";
+
+    private static class JavaClassComparator implements Comparator
+    {
+        public int compare(Object arg0, Object arg1)
+        {
+            JavaClass c0 = (JavaClass) arg0;
+            JavaClass c1 = (JavaClass) arg1;
+
+            return (c0.getFullyQualifiedName().compareTo(c1.getFullyQualifiedName()));
+        }
+    }
+
+    /**
+     * Scan the source tree for doc-annotations, and build Model objects
+     * containing info extracted from the doc-annotation attributes and
+     * introspected info about the item the annotation is attached to.
+     */
+    public void buildModel(Model model, MavenProject project)
+            throws MojoExecutionException
+    {
+        buildModel(model, project.getCompileSourceRoots());
+    }
+    
+    /**
+     * @since 1.0.2
+     */
+    public void buildModel(Model model, MavenProject project, String includes, String excludes)
+        throws MojoExecutionException
+    {
+        if (StringUtils.isNotEmpty(includes) || 
+                StringUtils.isNotEmpty(excludes))
+        {
+            buildModel(model, project.getCompileSourceRoots(),includes, excludes);            
+        }
+        else
+        {
+            buildModel(model, project.getCompileSourceRoots());
+        }
+    }
+    
+    /**
+     * @since 1.0.2
+     */
+    public void buildModel(Model model, List sourceDirs, String includes, String excludes)
+        throws MojoExecutionException
+    {
+        String currModelId = model.getModelId();
+        if (currModelId == null)
+        {
+            throw new MojoExecutionException("Model must have id set");
+        }
+
+        JavaDocBuilder builder = new JavaDocBuilder();
+
+        IncludeExcludeFileSelector selector = 
+            new IncludeExcludeFileSelector(); 
+    
+        if (StringUtils.isNotEmpty(excludes))
+        {
+            selector.setExcludes(excludes.split(","));
+        }
+        if (StringUtils.isNotEmpty(includes))
+        {
+            selector.setIncludes(includes.split(","));            
+        }
+        
+        for (Iterator i = sourceDirs.iterator(); i.hasNext();)
+        {
+            File srcDir = new File((String) i.next());
+            
+            //Scan all files on directory and add to builder
+            addFileToJavaDocBuilder(builder, selector, srcDir);
+        }        
+        
+        JavaClass[] classes = builder.getClasses();
+        
+        buildModel(model, sourceDirs, classes);
+    }
+    
+    private void addFileToJavaDocBuilder(JavaDocBuilder builder,
+            FileSelector selector, File path)
+    {
+        if (path.isDirectory())
+        {
+            File[] files = path.listFiles();
+            
+            //Scan all files in directory
+            for (int i = 0; i < files.length; i++)
+            {
+                addFileToJavaDocBuilder(builder, selector, files[i]);
+            }
+        }
+        else
+        {
+            File file = path;
+            try
+            {
+                if (selector.isSelected(new SourceFileInfo(file)))
+                {
+                    builder.addSource(file);
+                }
+            }
+            catch (FileNotFoundException e)
+            {
+                log.error("Error reading file: "+file.getName()+" "+e.getMessage());
+            }
+            catch (IOException e)
+            {
+                log.error("Error reading file: "+file.getName()+" "+e.getMessage());                
+            }
+        }
+    }
+    
+    private class SourceFileInfo implements FileInfo
+    {
+        private File file;
+        
+        private String name;
+
+        /**
+         * Creates a new instance.
+         */
+        public SourceFileInfo( File file )
+        {
+            this( file, file.getPath().replace( '\\', '/' ) );
+        }
+
+        /**
+         * Creates a new instance.
+         */
+        public SourceFileInfo( File file, String name )
+        {
+            this.file = file;
+            this.name = name;
+        }
+        
+        /**
+         * Sets the resources file.
+         */
+        public void setFile( File file )
+        {
+            this.file = file;
+        }
+
+        /**
+         * Returns the resources file.
+         */
+        public File getFile()
+        {
+            return file;
+        }
+
+        /**
+         * Sets the resources name.
+         */
+        public void setName( String name )
+        {
+            this.name = name;
+        }
+
+        public String getName()
+        {
+            return name;
+        }        
+        
+        public InputStream getContents() throws IOException
+        {
+            return new FileInputStream( getFile() );
+        }
+
+        public boolean isDirectory()
+        {
+            return file.isDirectory();
+        }
+
+        public boolean isFile()
+        {
+            return file.isFile();
+        }        
+    }
+
+    /**
+     * Scan the source tree for doc-annotations, and build Model objects
+     * containing info extracted from the doc-annotation attributes and
+     * introspected info about the item the annotation is attached to.
+     */
+    public void buildModel(Model model, List sourceDirs)
+            throws MojoExecutionException
+    {
+        String currModelId = model.getModelId();
+        if (currModelId == null)
+        {
+            throw new MojoExecutionException("Model must have id set");
+        }
+
+        JavaDocBuilder builder = new JavaDocBuilder();
+
+        // need a File object representing the original source tree
+        //
+        // TODO: make this more flexible, so specific classes can
+        // be included and excluded.
+        for (Iterator i = sourceDirs.iterator(); i.hasNext();)
+        {
+            String srcDir = (String) i.next();
+            builder.addSourceTree(new File(srcDir));
+        }
+
+        JavaClass[] classes = builder.getClasses();
+
+        buildModel(model, sourceDirs, classes);
+    }
+    
+    protected void buildModel(Model model, List sourceDirs, JavaClass[] classes)
+        throws MojoExecutionException
+    {
+        String currModelId = model.getModelId();
+
+        // Sort the class array so that they are processed in a
+        // predictable order, regardless of how the source scanning
+        // returned them.
+        Arrays.sort(classes, new JavaClassComparator());
+        Map processedClasses = new HashMap();
+        for (int i = 0; i < classes.length; ++i)
+        {
+            JavaClass clazz = classes[i];
+            processClass(processedClasses, clazz, model);
+        }
+
+        // Post-process the list of components which we added in this run.
+        // Note that model has all the inherited components in it too, so
+        // we need to skip them.
+        //
+        // Hmm..as noted elsewhere, JavaClass objects representing parent
+        // classes are accessable via getParentClazz(). Presumably they are
+        // not in the array returned by builder.getClasses() though..
+        for (Iterator it = model.getComponents().iterator(); it.hasNext();)
+        {
+            ComponentMeta component = (ComponentMeta) it.next();
+            if (!component.getModelId().equals(currModelId))
+            {
+                continue;
+            }
+            initComponentAncestry(processedClasses, model, component);
+
+            //Check if the component class java file exists in the source dirs
+            String classname = component.getClassName();
+            String classfile = StringUtils.replace(classname,".","/")+".java";
+            if (!IOUtils.existsSourceFile(classfile, sourceDirs))
+            {
+                component.setGeneratedComponentClass(Boolean.TRUE);
+            }
+
+            // Check if the tag class java file exists in the source dirs
+            if (isTagClassMissing(component.getTagClass(), sourceDirs))
+            {
+                component.setGeneratedTagClass(Boolean.TRUE);
+            }
+        }
+
+        // post-process the list of converters
+        for (Iterator it = model.getConverters().iterator(); it.hasNext();)
+        {
+            ConverterMeta converter = (ConverterMeta) it.next();
+            if (!converter.getModelId().equals(currModelId))
+            {
+                continue;
+            }
+            // TODO: why is there no check for Converter class existence here??
+            // ANS: there is no automatic generation of converter class.
+            
+            // Check if the tag class java file exists in the source dirs
+            if (isTagClassMissing(converter.getTagClass(), sourceDirs))
+            {
+                converter.setGeneratedTagClass(Boolean.TRUE);
+            }
+        }
+
+        // post-process the list of validators
+        for (Iterator it = model.getValidators().iterator(); it.hasNext();)
+        {
+            ValidatorMeta validator = (ValidatorMeta) it.next();
+            if (!validator.getModelId().equals(currModelId))
+            {
+                continue;
+            }
+            initValidatorAncestry(processedClasses, model, validator);
+            
+            //Check if the validator class file exists
+            if (!IOUtils.existsSourceFile(StringUtils.replace(
+                    validator.getClassName(),".","/")+".java", sourceDirs))
+            {
+                validator.setGeneratedComponentClass(Boolean.TRUE);
+            }
+
+            // Check if the tag class java file exists in the source dirs
+            if (isTagClassMissing(validator.getTagClass(), sourceDirs))
+            {
+                validator.setGeneratedTagClass(Boolean.TRUE);
+            }
+        }
+
+        // post-process the list of tags
+        for (Iterator it = model.getTags().iterator(); it.hasNext();)
+        {
+            TagMeta tag = (TagMeta) it.next();
+            // nothing to do at the moment 
+        }       
+
+    }
+
+    /**
+     * Returns true if the tagClassName is not null, but the corresponding
+     * source file cannot be found in the specified source dirs.
+     */
+    private boolean isTagClassMissing(String tagClassName, List sourceDirs)
+    {
+        if (tagClassName == null)
+        {
+            return false;
+        }
+        String tagClassFile = StringUtils.replace(tagClassName,".","/")+".java";
+        return !IOUtils.existsSourceFile(tagClassFile, sourceDirs);
+    }
+
+    /**
+     * Set the parentClassName and interfaceClassNames properties of the
+     * provided modelItem object.
+     */
+    private void processClass(Map processedClasses, JavaClass clazz, Model model)
+            throws MojoExecutionException
+    {
+        if (processedClasses.containsKey(clazz.getFullyQualifiedName()))
+        {
+            return;
+        }
+
+        // first, check that the parent type and all interfaces have been
+        // processed.
+        JavaClass parentClazz = clazz.getSuperJavaClass();
+        if (parentClazz != null)
+        {
+            processClass(processedClasses, parentClazz, model);
+        }
+
+        JavaClass[] classes = clazz.getImplementedInterfaces();
+        for (int i = 0; i < classes.length; ++i)
+        {
+            JavaClass iclazz = classes[i];
+            processClass(processedClasses, iclazz, model);
+        }
+
+        // ok, now we can mark this class as processed.
+        processedClasses.put(clazz.getFullyQualifiedName(), clazz);
+
+        log.info("processed class:" + clazz.getFullyQualifiedName());
+
+        DocletTag tag;
+        Annotation anno;
+
+        // converters
+        tag = clazz.getTagByName(DOC_CONVERTER, false);
+        if (tag != null)
+        {
+            Map props = tag.getNamedParameterMap();
+            processConverter(props, tag.getContext(), clazz, model);
+        }
+        anno = getAnnotation(clazz, DOC_CONVERTER);
+        if (anno != null)
+        {
+            Map props = anno.getNamedParameterMap();
+            processConverter(props, anno.getContext(), clazz, model);
+        }
+
+        // validators
+        tag = clazz.getTagByName(DOC_VALIDATOR, false);
+        if (tag != null)
+        {
+            Map props = tag.getNamedParameterMap();
+            processValidator(props, tag.getContext(), clazz, model);
+        }
+        anno = getAnnotation(clazz, DOC_VALIDATOR);
+        if (anno != null)
+        {
+            Map props = anno.getNamedParameterMap();
+            processValidator(props, anno.getContext(), clazz, model);
+        }
+
+        // components
+        tag = clazz.getTagByName(DOC_COMPONENT, false);
+        if (tag != null)
+        {
+            Map props = tag.getNamedParameterMap();
+            processComponent(props, tag.getContext(), clazz, model);
+        }
+        anno = getAnnotation(clazz, DOC_COMPONENT);
+        if (anno != null)
+        {
+            Map props = anno.getNamedParameterMap();
+            processComponent(props, anno.getContext(), clazz, model);
+        }
+        
+        //tag
+        tag = clazz.getTagByName(DOC_TAG, false);
+        if (tag != null)
+        {
+            Map props = tag.getNamedParameterMap();
+            processTag(props, tag.getContext(), clazz, model);
+        }
+        anno = getAnnotation(clazz, DOC_TAG);
+        if (anno != null)
+        {
+            Map props = anno.getNamedParameterMap();
+            processTag(props, anno.getContext(), clazz, model);
+        }
+        
+        // renderKit
+        tag = clazz.getTagByName(DOC_RENDERKIT, false);
+        if (tag != null)
+        {
+            Map props = tag.getNamedParameterMap();
+            processRenderKit(props, tag.getContext(), clazz, model);
+        }
+        anno = getAnnotation(clazz, DOC_RENDERKIT);
+        if (anno != null)
+        {
+            Map props = anno.getNamedParameterMap();
+            processRenderKit(props, anno.getContext(), clazz, model);
+        }
+                
+        // renderer
+        DocletTag [] tags = clazz.getTagsByName(DOC_RENDERER, false);
+        
+        for (int i = 0; i < tags.length; i++)
+        {
+            tag = tags[i];
+            if (tag != null)
+            {
+                Map props = tag.getNamedParameterMap();
+                processRenderer(props, tag.getContext(), clazz, model);
+            }
+        }
+        
+        anno = getAnnotation(clazz, DOC_RENDERER);
+        if (anno != null)
+        {
+            Map props = anno.getNamedParameterMap();
+            processRenderer(props, anno.getContext(), clazz, model);
+        }
+        
+        anno = getAnnotation(clazz, DOC_RENDERERS);
+        if (anno != null)
+        {
+            Object jspProps = anno.getNamedParameter("renderers");
+            
+            if (jspProps instanceof AnnoDef)
+            {
+                AnnoDef jspPropertiesAnno = (AnnoDef) jspProps;                
+                Map props = new NonParentesisMap(jspPropertiesAnno.args);
+                processRenderer(props, anno.getContext(), clazz, model);
+            }
+            else
+            {
+                List jspPropsList = (List) jspProps;
+                for (int i = 0; i < jspPropsList.size();i++)
+                {
+                    AnnoDef ranno = (AnnoDef) jspPropsList.get(i);
+                    
+                    Map props = new NonParentesisMap(ranno.args);
+                    processRenderer(props, anno.getContext(), clazz, model);
+                }
+            }
+        }
+    }
+
+    private Annotation getAnnotation(AbstractJavaEntity entity, String annoName)
+    {
+        Annotation[] annos = entity.getAnnotations();
+        if (annos == null)
+        {
+            return null;
+        }
+        // String wanted = ANNOTATION_BASE + "." + annoName;
+        for (int i = 0; i < annos.length; ++i)
+        {
+            Annotation thisAnno = annos[i];
+            // Ideally, here we would check whether the fully-qualified name of
+            // the annotation
+            // class matches ANNOTATION_BASE + "." + annoName. However it
+            // appears that qdox 1.6.3
+            // does not correctly expand @Foo using the class import statements;
+            // method
+            // Annotation.getType.getJavaClass.getFullyQualifiedName still just
+            // returns the short
+            // class name. So for now, just check for the short name.
+            String thisAnnoName = thisAnno.getType().getJavaClass().getName();
+            
+            //Make short name for recognizing, if returns long
+            int containsPoint = thisAnnoName.lastIndexOf('.');
+            if (containsPoint != -1)
+            {
+                thisAnnoName = thisAnnoName.substring(containsPoint+1);
+            }
+            if (thisAnnoName.equals(annoName))
+            {
+                return thisAnno;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Remove all leading whitespace and a quotemark if it exists.
+     * <p>
+     * Qdox comments like <code>foo val= "bar"</code> return a value with
+     * leading whitespace and quotes, so remove them.
+     */
+    private String clean(Object srcObj)
+    {
+        if (srcObj == null)
+        {
+            return null;
+        }
+
+        String src = srcObj.toString();
+        int start = 0;
+        int end = src.length();
+        
+        if (end == 0)
+        {
+            return src;
+        }
+        
+        if (src.equals("\"\""))
+        {
+            return "\"\"";
+        }
+
+        while (start <= end)
+        {
+            char c = src.charAt(start);
+            if (!Character.isWhitespace(c) && (c != '"'))
+            {
+                break;
+            }
+            ++start;
+        }
+        while (end >= start)
+        {
+            char c = src.charAt(end - 1);
+            if (!Character.isWhitespace(c) && (c != '"'))
+            {
+                break;
+            }
+            --end;
+        }
+        return src.substring(start, end);
+    }
+
+    /**
+     * Get the named attribute from a doc-annotation.
+     * 
+     * Param clazz is the class the annotation is attached to; only used when
+     * reporting errors.
+     */
+    private String getString(JavaClass clazz, String key, Map map, String dflt)
+    {
+        String val = clean(map.get(key));
+        if (val != null)
+        {
+            return val;
+        }
+        else
+        {
+            return dflt;
+        }
+    }
+
+    /**
+     * Get the named attribute from a doc-annotation and convert to a boolean.
+     * 
+     * Param clazz is the class the annotation is attached to; only used when
+     * reporting errors.
+     */
+    private Boolean getBoolean(JavaClass clazz, String key, Map map,
+            Boolean dflt)
+    {
+        String val = clean(map.get(key));
+        if (val == null)
+        {
+            return dflt;
+        }
+        // TODO: report problem if the value does not look like "true" or
+        // "false",
+        // rather than silently converting it to false.
+        return Boolean.valueOf(val);
+    }
+
+    /**
+     * Set the basic data on a ClassMeta.
+     * <p>
+     * There is one property not set here: the parentClassName. See method
+     * initComponentAncestry for further details.
+     */
+    private void initClassMeta(Model model, JavaClass clazz,
+            ClassMeta modelItem, String classNameOverride)
+    {
+        modelItem.setModelId(model.getModelId());
+        modelItem.setSourceClassName(clazz.getFullyQualifiedName());
+        JavaClass realParentClass = clazz.getSuperJavaClass();
+        if (realParentClass != null)
+        {
+            String fqn = realParentClass.getFullyQualifiedName();
+            if ((fqn != null) && !fqn.startsWith("java.lang"))
+            {
+                modelItem.setSourceClassParentClassName(fqn);
+            }
+        }
+
+        // JSF Entity class.
+        if (StringUtils.isEmpty(classNameOverride))
+        {
+            modelItem.setClassName(clazz.getFullyQualifiedName());
+        }
+        else
+        {
+            modelItem.setClassName(classNameOverride);
+        }
+
+        // interfaces metadata is inherited from
+        JavaClass[] classes = clazz.getImplementedInterfaces();
+        List ifaceNames = new ArrayList();
+        for (int i = 0; i < classes.length; ++i)
+        {
+            JavaClass iclazz = classes[i];
+
+            ComponentMeta ifaceComponent = model
+                    .findComponentByClassName(iclazz.getFullyQualifiedName());
+            if (ifaceComponent != null)
+            {
+                ifaceNames.add(ifaceComponent.getClassName());
+            }
+        }
+        modelItem.setInterfaceClassNames(ifaceNames);
+    }
+
+    /**
+     * For each component, try to find its "logical" parent component,
+     * ie the nearest superclass that is also annotated as a component
+     * and therefore has an entry in the model.
+     * <p>
+     * In most cases this could be done at the time the component is
+     * processed. The processClass() method does try to process the
+     * classes that qdox discovers in ancestor->descendant order.
+     * <p>
+     * However there is one case where this just doesn't work. Therefore
+     * a two-pass approach is used: first create a ComponentMeta for
+     * each component, and then on a second pass find the matching
+     * parent for each one.
+     * <p>
+     * The problem case is where an annotated java class extends a
+     * generated one. In this case when walking up the ancestry tree of
+     * the hand-written class we find an entry for which there is no
+     * ComponentMeta entry. We do not know whether this is because the
+     * parent exists but is not annotated, or whether a ComponentMeta
+     * for that parent will be generated once we have processed some
+     * other class that happens to have the matching annotation.
+     */
+    private void initComponentAncestry(Map javaClassByName, Model model, ClassMeta modelItem)
+    {
+        JavaClass clazz = (JavaClass) javaClassByName.get(modelItem.getSourceClassName());
+        JavaClass parentClazz = clazz.getSuperJavaClass();
+        while (parentClazz != null)
+        {
+            ComponentMeta parentComponent = model
+                    .findComponentByClassName(parentClazz.getFullyQualifiedName());
+            if (parentComponent != null)
+            {
+                modelItem.setParentClassName(parentComponent.getClassName());
+                break;
+            }
+            parentClazz = parentClazz.getSuperJavaClass();
+        }
+    }
+
+    /**
+     * Same as initComponentAncestry but for validators.
+     */
+    private void initValidatorAncestry(Map javaClassByName, Model model, ClassMeta modelItem)
+    {
+        JavaClass clazz = (JavaClass) javaClassByName.get(modelItem.getSourceClassName());
+        JavaClass parentClazz = clazz.getSuperJavaClass();
+        while (parentClazz != null)
+        {
+            ValidatorMeta parentComponent = model
+                    .findValidatorByClassName(parentClazz.getFullyQualifiedName());
+            if (parentComponent != null)
+            {
+                modelItem.setParentClassName(parentComponent.getClassName());
+                break;
+            }
+            parentClazz = parentClazz.getSuperJavaClass();
+        }
+    }    
+
+    private void processConverter(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, Model model)
+    {
+        String longDescription = clazz.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+
+        String converterIdDflt = null;
+        JavaField fieldConverterId = clazz
+                .getFieldByName("CONVERTER_ID");
+        if (fieldConverterId != null)
+        {
+            String value = fieldConverterId.getInitializationExpression();
+            converterIdDflt = clean(value.substring(value.indexOf('"')));
+        }        
+        String converterId = getString(clazz, "id", props, converterIdDflt);
+
+        // Check for both "class" and "clazz" in order to support
+        // doclet and real annotations.
+        String classNameOverride = getString(clazz, "class", props, null);
+        classNameOverride = getString(clazz,"clazz",props,classNameOverride);
+        
+        String componentName = getString(clazz, "name", props, null);
+        String bodyContent = getString(clazz, "bodyContent", props, null);
+        String tagClass = getString(clazz, "tagClass", props, null);
+        String tagSuperclass = getString(clazz, "tagSuperclass", props, null);
+        String serialuidtag = getString(clazz, "serialuidtag", props, null);
+        Boolean configExcluded = getBoolean(clazz,"configExcluded",props,null);   
+
+        ConverterMeta converter = new ConverterMeta();
+        initClassMeta(model, clazz, converter, classNameOverride);
+        converter.setName(componentName);
+        converter.setBodyContent(bodyContent);
+        converter.setTagClass(tagClass);
+        converter.setTagSuperclass(tagSuperclass);
+        converter.setConverterId(converterId);
+        converter.setDescription(shortDescription);
+        converter.setLongDescription(longDescription);
+        converter.setSerialuidtag(serialuidtag);
+        converter.setConfigExcluded(configExcluded);
+        
+        // Now here walk the component looking for property annotations.
+        processComponentProperties(clazz, converter);
+        
+        model.addConverter(converter);
+    }
+        
+    private void processValidator(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, Model model)
+    {
+        String longDescription = clazz.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+
+        String validatorIdDflt = null;
+        JavaField fieldConverterId = clazz
+                .getFieldByName("VALIDATOR_ID");
+        if (fieldConverterId != null)
+        {
+            String value = fieldConverterId.getInitializationExpression();
+            validatorIdDflt = clean(value.substring(value.indexOf('"')));
+        }        
+        String validatorId = getString(clazz, "id", props, validatorIdDflt);
+
+        // Check for both "class" and "clazz" in order to support
+        // doclet and real annotations.
+        String classNameOverride = getString(clazz, "class", props, null);
+        classNameOverride = getString(clazz,"clazz",props,classNameOverride);
+        
+        String componentName = getString(clazz, "name", props, null);
+        String bodyContent = getString(clazz, "bodyContent", props, null);
+        String tagClass = getString(clazz, "tagClass", props, null);        
+        String tagSuperclass = getString(clazz, "tagSuperclass", props, null);
+        String serialuidtag = getString(clazz, "serialuidtag", props, null);
+        Boolean configExcluded = getBoolean(clazz,"configExcluded",props,null);   
+        
+        ValidatorMeta validator = new ValidatorMeta();
+        initClassMeta(model, clazz, validator, classNameOverride);
+        validator.setName(componentName);
+        validator.setBodyContent(bodyContent);
+        validator.setTagClass(tagClass);
+        validator.setTagSuperclass(tagSuperclass);
+        validator.setValidatorId(validatorId);
+        validator.setDescription(shortDescription);
+        validator.setLongDescription(longDescription);
+        validator.setSerialuidtag(serialuidtag);
+        validator.setConfigExcluded(configExcluded);
+        
+        // Now here walk the component looking for property annotations.
+        processComponentProperties(clazz, validator);
+        
+        model.addValidator(validator);
+    }
+    
+    private void processRenderKit(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, Model model)
+    {
+
+        String renderKitId = getString(clazz, "renderKitId", props, null);
+        String renderKitClass = getString(clazz, "class", props, clazz
+                .getFullyQualifiedName());
+        renderKitClass = getString(clazz,"clazz",props,renderKitClass);
+
+        RenderKitMeta renderKit = model.findRenderKitById(renderKitId);
+        
+        if (renderKit == null)
+        {
+            renderKit = new RenderKitMeta();
+            renderKit.setClassName(renderKitClass);
+            renderKit.setRenderKitId(renderKitId);
+            model.addRenderKit(renderKit);        
+        }
+        else
+        {
+            renderKit.setClassName(renderKitClass);
+            renderKit.setRenderKitId(renderKitId);            
+        }
+    }
+    
+    private void processRenderer(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, Model model)
+    {
+        String longDescription = clazz.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+   
+        String renderKitId = getString(clazz, "renderKitId", props, null);
+        String rendererClass = getString(clazz, "class", props, clazz
+                .getFullyQualifiedName());
+        rendererClass = getString(clazz,"clazz",props,rendererClass);
+        
+        String componentFamily = getString(clazz,"family", props,null);
+        String rendererType = getString(clazz,"type", props,null);
+        
+        RenderKitMeta renderKit = model.findRenderKitById(renderKitId);
+        
+        if (renderKit == null)
+        {
+            renderKit = new RenderKitMeta();
+            renderKit.setRenderKitId(renderKitId);
+            model.addRenderKit(renderKit);            
+        }
+
+        RendererMeta renderer = new RendererMeta();
+        renderer.setClassName(rendererClass);
+        renderer.setDescription(shortDescription);
+        renderer.setComponentFamily(componentFamily);
+        renderer.setRendererType(rendererType);
+        renderKit.addRenderer(renderer);
+    }
+    
+    private void processTag(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, Model model) throws MojoExecutionException
+    {
+        String longDescription = clazz.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+
+        String tagName = getString(clazz, "name", props, null);
+        String classNameOverride = getString(clazz, "class", props, null);
+        classNameOverride = getString(clazz,"clazz",props,classNameOverride);
+        
+        String bodyContent = getString(clazz, "bodyContent", props, "JSP");
+        String tagHandler = getString(clazz, "tagHandler", props, null);
+
+        TagMeta tag = new TagMeta();
+        initClassMeta(model, clazz, tag, classNameOverride);
+        tag.setName(tagName);
+        tag.setBodyContent(bodyContent);
+        tag.setDescription(shortDescription);
+        tag.setLongDescription(longDescription);
+        tag.setTagHandler(tagHandler);
+        
+        processTagAttributes(clazz, tag);
+        model.addTag(tag);
+    }
+    
+    private void processComponent(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, Model model) throws MojoExecutionException
+    {
+        String componentTypeDflt = null;
+        JavaField fieldComponentType = clazz.getFieldByName("COMPONENT_TYPE");
+        if (fieldComponentType != null)
+        {
+            componentTypeDflt = clean(fieldComponentType
+                    .getInitializationExpression());
+        }
+
+        String componentTypeFamily = null;
+        JavaField fieldComponentFamily = clazz
+                .getFieldByName("COMPONENT_FAMILY");
+        if (fieldComponentFamily != null)
+        {
+            componentTypeFamily = clean(fieldComponentFamily
+                    .getInitializationExpression());
+        }
+
+        String rendererTypeDflt = null;
+        JavaField fieldRendererType = clazz
+                .getFieldByName("DEFAULT_RENDERER_TYPE");
+        if (fieldRendererType != null)
+        {
+            rendererTypeDflt = clean(fieldRendererType
+                    .getInitializationExpression());
+        }
+
+        String componentName = getString(clazz, "name", props, null);
+
+        // Check for both "class" and "clazz" in order to support
+        // doclet and real annotations.
+        String classNameOverride = getString(clazz, "class", props, null);
+        classNameOverride = getString(clazz,"clazz",props,classNameOverride);
+                
+        Boolean template = getBoolean(clazz,"template",props, null);
+                
+        String longDescription = clazz.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+
+        String bodyContent = getString(clazz, "bodyContent", props, null);
+        
+        String componentFamily = getString(clazz, "family", props,
+                componentTypeFamily);
+        String componentType = getString(clazz, "type", props,
+                componentTypeDflt);
+        String rendererType = getString(clazz, "defaultRendererType", props,
+                rendererTypeDflt);
+        Boolean canHaveChildren = getBoolean(clazz, "canHaveChildren", props, null);
+        Boolean configExcluded = getBoolean(clazz,"configExcluded",props,null);        
+
+        String tagClass = getString(clazz, "tagClass", props, null);
+        String tagSuperclass = getString(clazz, "tagSuperclass", props, null);
+        String tagHandler = getString(clazz, "tagHandler", props, null);
+        String serialuid = getString(clazz, "serialuid", props, null);
+        String implementsValue = getString(clazz, "implements", props, null);
+        implementsValue = getString(clazz, "implementz", props, implementsValue);
+
+        ComponentMeta component = new ComponentMeta();
+        initClassMeta(model, clazz, component, classNameOverride);
+        component.setName(componentName);
+        component.setBodyContent(bodyContent);
+        component.setDescription(shortDescription);
+        component.setLongDescription(longDescription);
+        component.setConfigExcluded(configExcluded);
+        component.setType(componentType);
+        component.setFamily(componentFamily);
+        component.setRendererType(rendererType);
+        component.setChildren(canHaveChildren);
+        component.setSerialuid(serialuid);
+        component.setImplements(implementsValue);
+        component.setTemplate(template);
+        
+        JavaClass[] interfaces = clazz.getImplementedInterfaces();
+        for (int i = 0; i < interfaces.length; ++i)
+        {
+            JavaClass iface = interfaces[i];
+            if (iface.getFullyQualifiedName().equals(
+                    "javax.faces.component.NamingContainer"))
+            {
+                component.setNamingContainer(Boolean.TRUE);
+                break;
+            }
+        }
+
+        component.setTagClass(tagClass);
+        component.setTagSuperclass(tagSuperclass);
+        component.setTagHandler(tagHandler);
+
+        // Now here walk the component looking for property annotations.
+        processComponentProperties(clazz, component);
+        processComponentFacets(clazz, component);
+
+        model.addComponent(component);
+    }
+
+    private void processTagAttributes(JavaClass clazz,
+            TagMeta ctag)
+    {
+        JavaMethod[] methods = clazz.getMethods();
+        for (int i = 0; i < methods.length; ++i)
+        {
+            JavaMethod method = methods[i];
+
+            DocletTag tag = method.getTagByName(DOC_JSP_ATTRIBUTE);
+            if (tag != null)
+            {
+                Map props = tag.getNamedParameterMap();
+                processTagAttribute(props, tag.getContext(), clazz,
+                        method, ctag);
+            }
+
+            Annotation anno = getAnnotation(method, DOC_JSP_ATTRIBUTE);
+            if (anno != null)
+            {
+                Map props = anno.getNamedParameterMap();
+                processTagAttribute(props, anno.getContext(), clazz,
+                        method, ctag);
+            }
+        }
+        
+        DocletTag[] jspProperties = clazz.getTagsByName(DOC_JSP_ATTRIBUTE);
+        for (int i = 0; i < jspProperties.length; ++i)
+        {
+            //We have here only doclets, because this part is only for
+            //solve problems with binding property on 1.1
+            DocletTag tag = jspProperties[i];
+            
+            Map props = tag.getNamedParameterMap();
+            processTagAttribute(props, tag.getContext(), clazz,
+                    ctag);
+            
+        }                
+    }
+    
+    private void processTagAttribute(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, JavaMethod method, TagMeta tag)
+    {
+        Boolean required = getBoolean(clazz, "required", props, null);
+        Boolean rtexprvalue = getBoolean(clazz, "rtexprvalue", props, null);
+
+        String longDescription = ctx.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+                
+        Type returnType = null;
+        
+        if (method.getName().startsWith("set"))
+        {
+            returnType = method.getParameters()[0].getType();
+        }
+        else
+        {
+            returnType = method.getReturns();
+        }
+        
+        String className = getString(clazz,"className",props, returnType.toString());
+        
+        AttributeMeta a = new AttributeMeta();
+        a.setName(methodToPropName(method.getName()));
+        a.setClassName(className);
+        a.setRequired(required);
+        a.setRtexprvalue(rtexprvalue);
+        a.setDescription(shortDescription);
+        a.setLongDescription(longDescription);
+        
+        tag.addAttribute(a);
+    }
+    
+    private void processTagAttribute(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, TagMeta tag)
+    {
+        Boolean required = getBoolean(clazz, "required", props, null);
+        Boolean rtexprvalue = getBoolean(clazz, "rtexprvalue", props, null);
+
+        String longDescription = getString(clazz, "longDescription", props, null);
+        String descDflt = longDescription;
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+                
+        String name = getString(clazz, "name", props, descDflt);
+        String className = getString(clazz, "className", props, descDflt);
+                
+        AttributeMeta a = new AttributeMeta();
+        a.setName(name);
+        a.setClassName(className);
+        a.setRequired(required);
+        a.setRtexprvalue(rtexprvalue);
+        a.setDescription(shortDescription);
+        a.setLongDescription(longDescription);
+        
+        tag.addAttribute(a);
+    }
+    
+
+    
+    /**
+     * Look for any methods on the specified class that are annotated as being
+     * component properties, and add metadata about them to the model.
+     */
+    private void processComponentProperties(JavaClass clazz,
+            PropertyHolder component)
+    {
+        JavaMethod[] methods = clazz.getMethods();
+        for (int i = 0; i < methods.length; ++i)
+        {
+            JavaMethod method = methods[i];
+
+            DocletTag tag = method.getTagByName(DOC_PROPERTY);
+            if (tag != null)
+            {
+                Map props = tag.getNamedParameterMap();
+                processComponentProperty(props, tag.getContext(), clazz,
+                        method, component);
+            }
+
+            Annotation anno = getAnnotation(method, DOC_PROPERTY);
+            if (anno != null)
+            {
+                Map props = anno.getNamedParameterMap();
+                processComponentProperty(props, anno.getContext(), clazz,
+                        method, component);
+            }
+        }
+        
+        Type [] interfaces = clazz.getImplements();
+        
+        //Scan interfaces for properties to be added to this component
+        //This feature allow us to have groups of functions.
+        for (int i = 0; i < interfaces.length;++i)
+        {
+            JavaClass intf = interfaces[i].getJavaClass();
+
+            //If the interfaces has a JSFComponent Doclet,
+            //this is managed in other way
+            if (intf.getTagByName(DOC_COMPONENT, false) == null)
+            {
+                JavaMethod[] intfmethods = intf.getMethods();
+                for (int j = 0; j < intfmethods.length; ++j)
+                {
+                    JavaMethod intfmethod = intfmethods[j];
+
+                    DocletTag tag = intfmethod.getTagByName(DOC_PROPERTY);
+                    if (tag != null)
+                    {
+                        Map props = tag.getNamedParameterMap();
+                        processInterfaceComponentProperty(props, tag.getContext(), 
+                                clazz, intfmethod, component);
+                    }
+
+                    Annotation anno = getAnnotation(intfmethod, DOC_PROPERTY);
+                    if (anno != null)
+                    {
+                        Map props = anno.getNamedParameterMap();
+                        processInterfaceComponentProperty(props, anno.getContext(),
+                                clazz, intfmethod, component);
+                    }
+                }
+            }
+        }
+
+        //Scan for properties defined only on jsp (special case on myfaces 1.1,
+        //this feature should not be used on typical situations)
+        DocletTag[] jspProperties = clazz.getTagsByName(DOC_JSP_PROPERTY);
+        for (int i = 0; i < jspProperties.length; ++i)
+        {
+            //We have here only doclets, because this part is only for
+            //solve problems with binding property on 1.1
+            DocletTag tag = jspProperties[i];
+            
+            Map props = tag.getNamedParameterMap();
+            processComponentJspProperty(props, tag.getContext(), clazz,
+                    component);
+        }
+        
+        Annotation jspPropertyAnno = getAnnotation(clazz, DOC_JSP_PROPERTY);
+        if (jspPropertyAnno != null)
+        {
+            Map props = jspPropertyAnno.getNamedParameterMap();
+            processComponentJspProperty(props, jspPropertyAnno.getContext(),
+                    clazz, component);
+        }
+        
+        
+        Annotation jspAnno = getAnnotation(clazz, DOC_JSP_PROPERTIES);        
+        if (jspAnno != null)
+        {
+            Object jspProps = jspAnno.getNamedParameter("properties");
+            
+            if (jspProps instanceof AnnoDef)
+            {
+                AnnoDef jspPropertiesAnno = (AnnoDef) jspProps;                
+                Map props = new NonParentesisMap(jspPropertiesAnno.args);
+                processComponentJspProperty(props, jspAnno.getContext(), clazz,
+                        component);               
+            }
+            else
+            {
+                List jspPropsList = (List) jspProps;
+                for (int i = 0; i < jspPropsList.size();i++)
+                {
+                    AnnoDef anno = (AnnoDef) jspPropsList.get(i);
+                    
+                    Map props = new NonParentesisMap(anno.args);
+                    processComponentJspProperty(props, jspAnno.getContext(), clazz,
+                            component);                    
+                }
+            }
+            
+        }
+    }
+    
+    /**
+     * This class uses delegate pattern to remove square parentesis 
+     * that appear when you get the arguments from an AnnoDef. I think
+     * is a design problem in the annotation feature of qdox (1.6.3).
+     * 
+     * TODO: change this on a future version of qdox!  
+     *
+     */
+    public class NonParentesisMap implements Map
+    {
+
+        Map _delegate = null;
+        public NonParentesisMap(Map delegate)
+        {
+            _delegate = delegate;
+        }
+        public void clear()
+        {
+            _delegate.clear();
+        }
+
+        public boolean containsKey(Object key)
+        {
+            return _delegate.containsKey(key);
+        }
+
+        public boolean containsValue(Object value)
+        {
+            return _delegate.containsValue(value);
+        }
+
+        public Set entrySet()
+        {
+            return _delegate.entrySet();
+        }
+
+        public Object get(Object key)
+        {
+            Object value = _delegate.get(key);
+            if (value == null)
+            {
+                return null;
+            }
+            if (value instanceof List)
+            {
+                return ((List) value).get(0);
+            }            
+            return value; 
+        }
+
+        public boolean isEmpty()
+        {
+            return _delegate.isEmpty();
+        }
+
+        public Set keySet()
+        {
+            return _delegate.keySet();
+        }
+
+        public Object put(Object arg0, Object arg1)
+        {
+            return _delegate.put(arg0, arg1);
+        }
+
+        public void putAll(Map arg0)
+        {
+            _delegate.putAll(arg0);
+        }
+
+        public Object remove(Object key)
+        {
+            return _delegate.remove(key);
+        }
+
+        public int size()
+        {
+            return _delegate.size();
+        }
+
+        public Collection values()
+        {
+            return _delegate.values();
+        }
+        
+    }
+    
+    private void processComponentFacets(JavaClass clazz,
+            FacetHolder component)
+    {
+        JavaMethod[] methods = clazz.getMethods();
+        for (int i = 0; i < methods.length; ++i)
+        {
+            JavaMethod method = methods[i];
+
+            DocletTag tag = method.getTagByName(DOC_FACET);
+            if (tag != null)
+            {
+                Map props = tag.getNamedParameterMap();
+                processComponentFacet(props, tag.getContext(), clazz,
+                        method, component);
+            }
+
+            Annotation anno = getAnnotation(method, DOC_FACET);
+            if (anno != null)
+            {
+                Map props = anno.getNamedParameterMap();
+                processComponentFacet(props, anno.getContext(), clazz,
+                        method, component);
+            }
+        }
+        
+        Type [] interfaces = clazz.getImplements();
+        
+        //Scan interfaces for properties to be added to this component
+        //This feature allow us to have groups of functions.
+        for (int i = 0; i < interfaces.length;++i)
+        {
+            JavaClass intf = interfaces[i].getJavaClass();
+
+            //If the interfaces has a JSFComponent Doclet,
+            //this is managed in other way
+            if (intf.getTagByName(DOC_COMPONENT, false) == null)
+            {
+                JavaMethod[] intfmethods = intf.getMethods();
+                for (int j = 0; j < intfmethods.length; ++j)
+                {
+                    JavaMethod intfmethod = intfmethods[j];
+
+                    DocletTag tag = intfmethod.getTagByName(DOC_FACET);
+                    if (tag != null)
+                    {
+                        Map props = tag.getNamedParameterMap();
+                        processInterfaceComponentFacet(props, tag.getContext(), 
+                                clazz, intfmethod, component);
+                    }
+
+                    Annotation anno = getAnnotation(intfmethod, DOC_FACET);
+                    if (anno != null)
+                    {
+                        Map props = anno.getNamedParameterMap();
+                        processInterfaceComponentFacet(props, anno.getContext(),
+                                clazz, intfmethod, component);
+                    }
+                }
+            }
+        }
+    }
+        
+    private void processInterfaceComponentProperty(Map props, AbstractJavaEntity ctx,
+    JavaClass clazz, JavaMethod method, PropertyHolder component)
+    {
+        this.processComponentProperty(props, ctx, clazz, method, component);
+        
+        PropertyMeta property = component.getProperty(methodToPropName(method.getName()));
+        
+        //Try to get the method from the component clazz to see if this
+        //has an implementation
+        JavaMethod clazzMethod = clazz.getMethodBySignature(method.getName(), null , false);
+        
+        if (clazzMethod == null)
+        {
+            //The method should be generated!
+            property.setGenerated(Boolean.TRUE);
+        }            
+    }
+
+    private void processInterfaceComponentFacet(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, JavaMethod method, FacetHolder component)
+    {
+        this.processComponentFacet(props, ctx, clazz, method, component);
+                
+        FacetMeta facet = component.getFacet(methodToPropName(method.getName()));
+                
+        //Try to get the method from the component clazz to see if this
+        //has an implementation
+        JavaMethod clazzMethod = clazz.getMethodBySignature(method.getName(), null , false);
+                
+        if (clazzMethod == null)
+        {
+            //The method should be generated!
+            facet.setGenerated(Boolean.TRUE);
+        }            
+    }
+    
+    private void processComponentProperty(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, JavaMethod method, PropertyHolder component)
+    {
+        Boolean required = getBoolean(clazz, "required", props, null);
+        Boolean transientProp = getBoolean(clazz, "transient", props, null);
+        transientProp = getBoolean(clazz, "istransient", props, transientProp);
+        Boolean stateHolder = getBoolean(clazz, "stateHolder", props, null);
+        Boolean literalOnly = getBoolean(clazz, "literalOnly", props, null);
+        Boolean tagExcluded = getBoolean(clazz, "tagExcluded", props, null);
+        Boolean localMethod = getBoolean(clazz, "localMethod",props,null);
+        Boolean setMethod = getBoolean(clazz, "setMethod",props,null);
+        String localMethodScope = getString(clazz, "localMethodScope",props,null);
+        String setMethodScope = getString(clazz, "setMethodScope",props,null);
+        Boolean inheritedTag = getBoolean(clazz, "inheritedTag",props,null);
+
+        String longDescription = ctx.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+        String returnSignature = getString(clazz, "returnSignature", props, null);
+        String methodSignature = getString(clazz, "methodSignature", props, null);
+        String defaultValue = getString(clazz,"defaultValue",props,null);
+        String jspName = getString(clazz,"jspName",props,null);
+        Boolean rtexprvalue = getBoolean(clazz, "rtexprvalue",props,null);
+
+        Type returnType = null;
+        
+        if (method.getName().startsWith("set"))
+        {
+            returnType = method.getParameters()[0].getType();
+        }
+        else
+        {
+            returnType = method.getReturns();
+        }
+        
+        
+        PropertyMeta p = new PropertyMeta();
+        p.setName(methodToPropName(method.getName()));
+        p.setClassName(returnType.toString());
+        p.setRequired(required);
+        p.setTransient(transientProp);
+        p.setStateHolder(stateHolder);
+        p.setLiteralOnly(literalOnly);
+        p.setTagExcluded(tagExcluded);
+        p.setDescription(shortDescription);
+        p.setLongDescription(longDescription);
+        p.setDefaultValue(defaultValue);
+        p.setLocalMethod(localMethod);
+        p.setLocalMethodScope(localMethodScope);
+        p.setSetMethod(setMethod);
+        p.setSetMethodScope(setMethodScope);
+        p.setJspName(jspName);
+        p.setRtexprvalue(rtexprvalue);
+        p.setInheritedTag(inheritedTag);
+        
+        if (returnSignature != null)
+        {
+            MethodSignatureMeta signature = new MethodSignatureMeta();
+            signature.setReturnType(returnSignature);
+            
+            if (methodSignature != null)
+            {
+                String[] params = StringUtils.split(methodSignature,',');
+                
+                if (params != null)
+                {
+                    for (int i = 0; i < params.length; i++)
+                    {
+                        signature.addParameterType(params[i].trim());
+                    }
+                }
+            }
+            p.setMethodBindingSignature(signature);
+        }
+        
+        //If the method is abstract this should be generated
+        if (method.isAbstract())
+        {
+            p.setGenerated(Boolean.TRUE);
+        }
+
+        component.addProperty(p);
+    }
+    
+    private void processComponentFacet(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, JavaMethod method, FacetHolder component)
+    {
+        Boolean required = getBoolean(clazz, "required", props, null);
+
+        String longDescription = ctx.getComment();
+        String descDflt = getFirstSentence(longDescription);
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+        
+        FacetMeta p = new FacetMeta();
+        p.setName(methodToPropName(method.getName()));
+        p.setRequired(required);
+        p.setDescription(shortDescription);
+        p.setLongDescription(longDescription);
+        
+        //If the method is abstract this should be generated
+        if (method.isAbstract())
+        {
+            p.setGenerated(Boolean.TRUE);
+        }
+
+        component.addFacet(p);
+    }
+    
+    
+    private void processComponentJspProperty(Map props, AbstractJavaEntity ctx,
+            JavaClass clazz, PropertyHolder component)
+    {
+        Boolean required = getBoolean(clazz, "required", props, null);
+        Boolean transientProp = getBoolean(clazz, "transient", props, null);
+        Boolean stateHolder = getBoolean(clazz, "stateHolder", props, null);
+        Boolean literalOnly = getBoolean(clazz, "literalOnly", props, null);
+        Boolean tagExcluded = getBoolean(clazz, "tagExcluded", props, null);
+        Boolean inheritedTag = getBoolean(clazz, "inheritedTag", props, null);
+
+        String longDescription = getString(clazz, "longDesc", props, null);
+        
+        String descDflt = longDescription;
+        if ((descDflt == null) || (descDflt.length() < 2))
+        {
+            descDflt = "no description";
+        }
+        String shortDescription = getString(clazz, "desc", props, descDflt);
+        String returnType = getString(clazz, "returnType", props, null);
+        String name = getString(clazz, "name", props, null);
+        
+        PropertyMeta p = new PropertyMeta();
+        p.setName(name);
+        p.setClassName(returnType);
+        p.setRequired(required);
+        p.setTransient(transientProp);
+        p.setStateHolder(stateHolder);
+        p.setLiteralOnly(literalOnly);
+        p.setTagExcluded(tagExcluded);
+        p.setInheritedTag(inheritedTag);
+        p.setDescription(shortDescription);
+        p.setLongDescription(longDescription);
+        
+        p.setGenerated(Boolean.FALSE);
+
+        component.addProperty(p);
+    }
+    
+
+    /**
+     * Convert a method name to a property name.
+     */
+    static String methodToPropName(String methodName)
+    {
+        StringBuffer name = new StringBuffer();
+        if (methodName.startsWith("get") || methodName.startsWith("set"))
+        {
+            name.append(methodName.substring(3));
+        }
+        else if (methodName.startsWith("is"))
+        {
+            name.append(methodName.substring(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("Invalid annotated method name "
+                    + methodName);
+        }
+
+        // Handle following styles of property name
+        // getfooBar --> fooBar
+        // getFooBar --> fooBar
+        // getURL --> url
+        // getURLLocation --> urlLocation
+        for (int i = 0; i < name.length(); ++i)
+        {
+            char c = name.charAt(i);
+            if (Character.isUpperCase(c))
+            {
+                name.setCharAt(i, Character.toLowerCase(c));
+            }
+            else
+            {
+                if (i > 1)
+                {
+                    // reset the previous char to uppercase
+                    c = name.charAt(i - 1);
+                    name.setCharAt(i - 1, Character.toUpperCase(c));
+                }
+                break;
+            }
+        }
+        return name.toString();
+    }
+
+    /**
+     * Given the full javadoc for a component, extract just the "first
+     * sentence".
+     * <p>
+     * Initially, just find the first dot, and strip out any linefeeds. Later,
+     * try to handle "e.g." and similar (see javadoc algorithm for sentence
+     * detection).
+     */
+    private String getFirstSentence(String doc)
+    {
+        if (doc == null)
+        {
+            return null;
+        }
+
+        int index = doc.indexOf('.');
+        if (index == -1)
+        {
+            return doc;
+        }
+        // abc.
+        return doc.substring(0, index);
+    }
+}
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/AbstractDependencyMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/AbstractDependencyMojo.java
new file mode 100644
index 0000000..e22f640
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/AbstractDependencyMojo.java
@@ -0,0 +1,416 @@
+/*
+ *  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.unpack;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.List;
+
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.resolver.ArtifactCollector;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.dependency.utils.DependencySilentLog;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.UnArchiver;
+import org.codehaus.plexus.archiver.manager.ArchiverManager;
+import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
+import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.ReflectionUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @version $Id: AbstractDependencyMojo.java 552528
+ *          2007-07-02 16:12:47Z markh $
+ */
+public abstract class AbstractDependencyMojo
+    extends AbstractMojo
+{
+    /**
+     * Used to look up Artifacts in the remote repository.
+     * 
+     * @parameter expression="${component.org.apache.maven.artifact.factory.ArtifactFactory}"
+     * @required
+     * @readonly
+     */
+    protected org.apache.maven.artifact.factory.ArtifactFactory factory;
+
+    /**
+     * Used to look up Artifacts in the remote repository.
+     * 
+     * @parameter expression="${component.org.apache.maven.artifact.resolver.ArtifactResolver}"
+     * @required
+     * @readonly
+     */
+    protected org.apache.maven.artifact.resolver.ArtifactResolver resolver;
+
+    /**
+     * Artifact collector, needed to resolve dependencies.
+     * 
+     * @component role="org.apache.maven.artifact.resolver.ArtifactCollector"
+     * @required
+     * @readonly
+     */
+    protected ArtifactCollector artifactCollector;
+
+    /**
+     * @component role="org.apache.maven.artifact.metadata.ArtifactMetadataSource"
+     *            hint="maven"
+     * @required
+     * @readonly
+     */
+    protected ArtifactMetadataSource artifactMetadataSource;
+
+    /**
+     * Location of the local repository.
+     * 
+     * @parameter expression="${localRepository}"
+     * @readonly
+     * @required
+     */
+    protected org.apache.maven.artifact.repository.ArtifactRepository local;
+
+    /**
+     * List of Remote Repositories used by the resolver
+     * 
+     * @parameter expression="${project.remoteArtifactRepositories}"
+     * @readonly
+     * @required
+     */
+    protected java.util.List remoteRepos;
+
+    /**
+     * To look up Archiver/UnArchiver implementations
+     * 
+     * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
+     * @required
+     * @readonly
+     */
+    protected ArchiverManager archiverManager;
+
+    /**
+     * POM
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     * @required
+     */
+    protected MavenProject project;
+
+    /**
+     * Contains the full list of projects in the reactor.
+     * 
+     * @parameter expression="${reactorProjects}"
+     * @required
+     * @readonly
+     */
+    protected List reactorProjects;
+
+    /**
+     * If the plugin should be silent.
+     * 
+     * @optional
+     * @since 2.0
+     * @parameter expression="${silent}"
+     *            default-value="false"
+     */
+    public boolean silent;
+
+    /**
+     * Output absolute filename for resolved artifacts
+     * 
+     * @optional
+     * @since 2.0
+     * @parameter expression="${outputAbsoluteArtifactFilename}"
+     *            default-value="false"
+     */
+    protected boolean outputAbsoluteArtifactFilename;
+
+    private Log log;
+
+    /**
+     * @return Returns the log.
+     */
+    public Log getLog ()
+    {
+        if ( silent )
+        {
+            log = new DependencySilentLog();
+        }
+        else
+        {
+            log = super.getLog();
+        }
+
+        return this.log;
+    }
+
+    /**
+     * @return Returns the archiverManager.
+     */
+    public ArchiverManager getArchiverManager ()
+    {
+        return this.archiverManager;
+    }
+
+    /**
+     * Does the actual copy of the file and logging.
+     * 
+     * @param artifact represents the file to copy.
+     * @param destFile file name of destination file.
+     * 
+     * @throws MojoExecutionException with a message if an
+     *             error occurs.
+     */
+    protected void copyFile ( File artifact, File destFile )
+        throws MojoExecutionException
+    {
+        Log theLog = this.getLog();
+        try
+        {
+            theLog.info( "Copying "
+                + ( this.outputAbsoluteArtifactFilename ? artifact.getAbsolutePath() : artifact.getName() ) + " to "
+                + destFile );
+            FileUtils.copyFile( artifact, destFile );
+
+        }
+        catch ( Exception e )
+        {
+            throw new MojoExecutionException( "Error copying artifact from " + artifact + " to " + destFile, e );
+        }
+    }
+
+    protected void unpack ( File file, File location )
+        throws MojoExecutionException
+    {
+        unpack( file, location, null, null );
+    }
+
+    /**
+     * Unpacks the archive file.
+     * 
+     * @param file File to be unpacked.
+     * @param location Location where to put the unpacked
+     *            files.
+     * @param includes Comma separated list of file patterns
+     *            to include i.e. **\/*.xml,
+     *            **\/*.properties
+     * @param excludes Comma separated list of file patterns
+     *            to exclude i.e. **\/*.xml,
+     *            **\/*.properties
+     */
+    protected void unpack ( File file, File location, String includes, String excludes )
+        throws MojoExecutionException
+    {
+        try
+        {
+            getLog().info(
+                            "Unpacking " + file.getPath() + "to\n " + location.getPath()
+                                + "\nwith Includes " + includes + " and excludes:" + excludes );
+
+            location.mkdirs();
+
+            UnArchiver unArchiver;
+
+            unArchiver = archiverManager.getUnArchiver( file );
+
+            unArchiver.setSourceFile( file );
+
+            unArchiver.setDestDirectory( location );
+
+            if ( StringUtils.isNotEmpty( excludes ) || StringUtils.isNotEmpty( includes ) )
+            {
+                // Create the selectors that will filter
+                // based on include/exclude parameters
+                // MDEP-47
+                IncludeExcludeFileSelector[] selectors = new IncludeExcludeFileSelector[]
+                    {
+                        new IncludeExcludeFileSelector() 
+                    };
+
+                if ( StringUtils.isNotEmpty( excludes ) )
+                {
+                    selectors[0].setExcludes( excludes.split( "," ) );
+                }
+
+                if ( StringUtils.isNotEmpty( includes ) )
+                {
+                    selectors[0].setIncludes( includes.split( "," ) );
+                }
+
+                unArchiver.setFileSelectors( selectors );
+            }
+            if ( this.silent )
+            {
+                silenceUnarchiver( unArchiver );
+            }
+
+            unArchiver.extract();
+        }
+        catch ( NoSuchArchiverException e )
+        {
+            throw new MojoExecutionException( "Unknown archiver type", e );
+        }
+        catch ( ArchiverException e )
+        {
+            e.printStackTrace();
+            throw new MojoExecutionException( "Error unpacking file: " + file + " to: " + location + "\r\n"
+                + e.toString(), e );
+        }
+    }
+
+    private void silenceUnarchiver ( UnArchiver unArchiver )
+    {
+        // dangerous but handle any errors. It's the only
+        // way to silence the
+        // unArchiver.
+        try
+        {
+            Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( "logger", unArchiver.getClass() );
+
+            field.setAccessible( true );
+
+            field.set( unArchiver, this.getLog() );
+        }
+        catch ( Exception e )
+        {
+            // was a nice try. Don't bother logging because
+            // the log is silent.
+        }
+    }
+
+    /**
+     * @return Returns the factory.
+     */
+    public org.apache.maven.artifact.factory.ArtifactFactory getFactory ()
+    {
+        return this.factory;
+    }
+
+    /**
+     * @param factory The factory to set.
+     */
+    public void setFactory ( org.apache.maven.artifact.factory.ArtifactFactory factory )
+    {
+        this.factory = factory;
+    }
+
+    /**
+     * @return Returns the project.
+     */
+    public MavenProject getProject ()
+    {
+        return this.project;
+    }
+
+    /**
+     * @return Returns the local.
+     */
+    public org.apache.maven.artifact.repository.ArtifactRepository getLocal ()
+    {
+        return this.local;
+    }
+
+    /**
+     * @param local The local to set.
+     */
+    public void setLocal ( org.apache.maven.artifact.repository.ArtifactRepository local )
+    {
+        this.local = local;
+    }
+
+    /**
+     * @return Returns the remoteRepos.
+     */
+    public java.util.List getRemoteRepos ()
+    {
+        return this.remoteRepos;
+    }
+
+    /**
+     * @param remoteRepos The remoteRepos to set.
+     */
+    public void setRemoteRepos ( java.util.List remoteRepos )
+    {
+        this.remoteRepos = remoteRepos;
+    }
+
+    /**
+     * @return Returns the resolver.
+     */
+    public org.apache.maven.artifact.resolver.ArtifactResolver getResolver ()
+    {
+        return this.resolver;
+    }
+
+    /**
+     * @param resolver The resolver to set.
+     */
+    public void setResolver ( org.apache.maven.artifact.resolver.ArtifactResolver resolver )
+    {
+        this.resolver = resolver;
+    }
+
+    /**
+     * @param archiverManager The archiverManager to set.
+     */
+    public void setArchiverManager ( ArchiverManager archiverManager )
+    {
+        this.archiverManager = archiverManager;
+    }
+
+    /**
+     * @return Returns the artifactCollector.
+     */
+    public ArtifactCollector getArtifactCollector ()
+    {
+        return this.artifactCollector;
+    }
+
+    /**
+     * @param theArtifactCollector The artifactCollector to
+     *            set.
+     */
+    public void setArtifactCollector ( ArtifactCollector theArtifactCollector )
+    {
+        this.artifactCollector = theArtifactCollector;
+    }
+
+    /**
+     * @return Returns the artifactMetadataSource.
+     */
+    public ArtifactMetadataSource getArtifactMetadataSource ()
+    {
+        return this.artifactMetadataSource;
+    }
+
+    /**
+     * @param theArtifactMetadataSource The
+     *            artifactMetadataSource to set.
+     */
+    public void setArtifactMetadataSource ( ArtifactMetadataSource theArtifactMetadataSource )
+    {
+        this.artifactMetadataSource = theArtifactMetadataSource;
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/AbstractFromConfigurationMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/AbstractFromConfigurationMojo.java
new file mode 100644
index 0000000..58c89cc
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/AbstractFromConfigurationMojo.java
@@ -0,0 +1,434 @@
+/*
+ *  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.unpack;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.MojoExecutionException;
+//import org.apache.maven.plugin.dependency.fromConfiguration.ArtifactItem;
+import org.apache.maven.plugin.dependency.utils.DependencyUtil;
+import org.apache.maven.plugin.dependency.utils.filters.ArtifactItemFilter;
+import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Abstract Parent class used by mojos that get Artifact information from the
+ * plugin configuration as an ArrayList of ArtifactItems
+ * 
+ * @see ArtifactItem
+ * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @version $Id$
+ * 
+ */
+public abstract class AbstractFromConfigurationMojo
+    extends AbstractDependencyMojo
+{
+
+    /**
+     * Default location used for mojo unless overridden in ArtifactItem
+     * 
+     * @parameter expression="${outputDirectory}"
+     *            default-value="${project.build.directory}/dependency"
+     * @optional
+     * @since 1.0
+     */
+    private File outputDirectory;
+
+    /**
+     * Overwrite release artifacts
+     * 
+     * @optional
+     * @since 1.0
+     * @parameter expression="${mdep.overWriteReleases}" default-value="false"
+     */
+    private boolean overWriteReleases;
+
+    /**
+     * Overwrite snapshot artifacts
+     * 
+     * @optional
+     * @since 1.0
+     * @parameter expression="${mdep.overWriteSnapshots}" default-value="false"
+     */
+    private boolean overWriteSnapshots;
+
+    /**
+     * Overwrite if newer
+     * 
+     * @optional
+     * @since 2.0
+     * @parameter expression="${mdep.overIfNewer}" default-value="true"
+     */
+    private boolean overWriteIfNewer;
+
+    /**
+     * Collection of ArtifactItems to work on. (ArtifactItem contains groupId,
+     * artifactId, version, type, classifier, location, destFile, markerFile and overwrite.)
+     * See "Usage" and "Javadoc" for details.
+     * 
+     * @parameter
+     * @required
+     * @since 1.0
+     */
+    private ArrayList artifactItems;
+
+    abstract ArtifactItemFilter getMarkedArtifactFilter( ArtifactItem item );
+
+    /**
+     * Preprocesses the list of ArtifactItems. This method defaults the
+     * outputDirectory if not set and creates the output Directory if it doesn't
+     * exist.
+     * 
+     * @param removeVersion
+     *            remove the version from the filename.
+     * @return An ArrayList of preprocessed ArtifactItems
+     * 
+     * @throws MojoExecutionException
+     *             with a message if an error occurs.
+     * 
+     * @see ArtifactItem
+     */
+    protected ArrayList getProcessedArtifactItems( boolean removeVersion )
+        throws MojoExecutionException
+    {
+        if ( artifactItems == null || artifactItems.size() < 1 )
+        {
+            throw new MojoExecutionException( "There are no artifactItems configured." );
+        }
+
+        Iterator iter = artifactItems.iterator();
+        while ( iter.hasNext() )
+        {
+            ArtifactItem artifactItem = (ArtifactItem) iter.next();
+            this.getLog().info( "Configured Artifact: " + artifactItem.toString() );
+
+            if ( artifactItem.getOutputDirectory() == null )
+            {
+                artifactItem.setOutputDirectory( this.outputDirectory );
+            }
+            artifactItem.getOutputDirectory().mkdirs();
+
+            // make sure we have a version.
+            if ( StringUtils.isEmpty( artifactItem.getVersion() ) )
+            {
+                fillMissingArtifactVersion( artifactItem );
+            }
+
+            artifactItem.setArtifact( this.getArtifact( artifactItem ) );
+
+            if ( StringUtils.isEmpty( artifactItem.getDestFileName() ) )
+            {
+                artifactItem.setDestFileName( DependencyUtil.getFormattedFileName( artifactItem.getArtifact(),
+                                                                                   removeVersion ) );
+            }
+
+            try
+            {
+                artifactItem.setNeedsProcessing( checkIfProcessingNeeded( artifactItem ) );
+            }
+            catch ( ArtifactFilterException e )
+            {
+                throw new MojoExecutionException (e.getMessage(),e);
+            }
+        }
+        return artifactItems;
+    }
+
+    private boolean checkIfProcessingNeeded( ArtifactItem item )
+        throws MojoExecutionException, ArtifactFilterException
+    {
+        boolean result = false;
+        if ( StringUtils.equalsIgnoreCase( item.getOverWrite(), "true" ) )
+        {
+            result = true;
+        }
+        else
+        {
+            ArtifactItemFilter filter = getMarkedArtifactFilter( item );
+            result = filter.isArtifactIncluded( item );
+        }
+        return result;
+    }
+
+    /**
+     * Resolves the Artifact from the remote repository if nessessary. If no
+     * version is specified, it will be retrieved from the dependency list or
+     * from the DependencyManagement section of the pom.
+     * 
+     * @param artifactItem
+     *            containing information about artifact from plugin
+     *            configuration.
+     * @return Artifact object representing the specified file.
+     * 
+     * @throws MojoExecutionException
+     *             with a message if the version can't be found in
+     *             DependencyManagement.
+     */
+    protected Artifact getArtifact( ArtifactItem artifactItem )
+        throws MojoExecutionException
+    {
+        Artifact artifact;
+
+        // Map managedVersions = createManagedVersionMap( factory,
+        // project.getId(), project.getDependencyManagement() );
+        VersionRange vr;
+        try
+        {
+            vr = VersionRange.createFromVersionSpec( artifactItem.getVersion() );
+        }
+        catch ( InvalidVersionSpecificationException e1 )
+        {
+            // TODO Auto-generated catch block
+            e1.printStackTrace();
+            vr = VersionRange.createFromVersion( artifactItem.getVersion() );
+        }
+
+        if ( StringUtils.isEmpty( artifactItem.getClassifier() ) )
+        {
+            artifact = factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
+                                                         artifactItem.getType(), null, Artifact.SCOPE_COMPILE );
+        }
+        else
+        {
+            artifact = factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
+                                                         artifactItem.getType(), artifactItem.getClassifier(),
+                                                         Artifact.SCOPE_COMPILE );
+        }
+
+        try
+        {
+            // mdep-50 - rolledback for now because it's breaking some
+            // functionality.
+            /*
+             * List listeners = new ArrayList();
+             * 
+             * Set theSet = new HashSet(); theSet.add( artifact );
+             * ArtifactResolutionResult artifactResolutionResult =
+             * artifactCollector.collect( theSet, project .getArtifact(),
+             * managedVersions, this.local,
+             * project.getRemoteArtifactRepositories(), artifactMetadataSource,
+             * null, listeners ); Iterator iter =
+             * artifactResolutionResult.getArtifactResolutionNodes().iterator();
+             * while ( iter.hasNext() ) { ResolutionNode node = (ResolutionNode)
+             * iter.next(); artifact = node.getArtifact(); }
+             */
+
+            resolver.resolve( artifact, remoteRepos, local );
+        }
+        catch ( ArtifactResolutionException e )
+        {
+            throw new MojoExecutionException( "Unable to resolve artifact.", e );
+        }
+        catch ( ArtifactNotFoundException e )
+        {
+            throw new MojoExecutionException( "Unable to find artifact.", e );
+        }
+
+        return artifact;
+    }
+
+    /**
+     * Tries to find missing version from dependancy list and dependency
+     * management. If found, the artifact is updated with the correct version.
+     * 
+     * It will first look for an exact match on artifactId/groupId/classifier/type and if it doesn't find
+     * a match, it will try again looking for artifactId and groupId only.
+     * @param artifact
+     *            representing configured file.
+     * @throws MojoExecutionException
+     */
+    private void fillMissingArtifactVersion( ArtifactItem artifact )
+        throws MojoExecutionException
+    {
+        if ( !findDependencyVersion( artifact, project.getDependencies(), false )
+            && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, project
+                .getDependencyManagement().getDependencies(), false ) )
+            && !findDependencyVersion( artifact, project.getDependencies(), true )
+            && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, project
+                .getDependencyManagement().getDependencies(), true ) ) )
+        {
+            throw new MojoExecutionException( "Unable to find artifact version of " + artifact.getGroupId() + ":"
+                + artifact.getArtifactId() + " in either dependency list or in project's dependency management." );
+        }
+    }
+
+    /**
+     * Tries to find missing version from a list of dependencies. If found, the
+     * artifact is updated with the correct version.
+     * 
+     * @param artifact
+     *            representing configured file.
+     * @param list
+     *            list of dependencies to search.
+     * @param looseMatch
+     *            only look at artifactId and groupId
+     * @return the found dependency
+     */
+    private boolean findDependencyVersion( ArtifactItem artifact, List list, boolean looseMatch )
+    {
+        boolean result = false;
+
+        for ( int i = 0; i < list.size(); i++ )
+        {
+            Dependency dependency = (Dependency) list.get( i );
+            if ( StringUtils.equals( dependency.getArtifactId(), artifact.getArtifactId() )
+                && StringUtils.equals( dependency.getGroupId(), artifact.getGroupId() )
+                && ( looseMatch || StringUtils.equals( dependency.getClassifier(), artifact.getClassifier() ) )
+                && ( looseMatch || StringUtils.equals( dependency.getType(), artifact.getType() ) ) )
+            {
+
+                artifact.setVersion( dependency.getVersion() );
+
+                result = true;
+                break;
+            }
+        }
+
+        return result;
+    }
+
+   /* private Map createManagedVersionMap( ArtifactFactory artifactFactory, String projectId,
+                                         DependencyManagement dependencyManagement )
+        throws MojoExecutionException
+    {
+        Map map;
+        if ( dependencyManagement != null && dependencyManagement.getDependencies() != null )
+        {
+            map = new HashMap();
+            for ( Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext(); )
+            {
+                Dependency d = (Dependency) i.next();
+
+                try
+                {
+                    VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
+                    Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(),
+                                                                                  versionRange, d.getType(), d
+                                                                                      .getClassifier(), d.getScope(), d
+                                                                                      .isOptional() );
+                    map.put( d.getManagementKey(), artifact );
+                }
+                catch ( InvalidVersionSpecificationException e )
+                {
+                    throw new MojoExecutionException( "Unable to parse version", e );
+                }
+            }
+        }
+        else
+        {
+            map = Collections.EMPTY_MAP;
+        }
+        return map;
+    }*/
+
+    /**
+     * @return Returns the artifactItems.
+     */
+    public ArrayList getArtifactItems()
+    {
+        return this.artifactItems;
+    }
+
+    /**
+     * @param theArtifactItems
+     *            The artifactItems to set.
+     */
+    public void setArtifactItems( ArrayList theArtifactItems )
+    {
+        this.artifactItems = theArtifactItems;
+    }
+
+    /**
+     * @return Returns the outputDirectory.
+     */
+    public File getOutputDirectory()
+    {
+        return this.outputDirectory;
+    }
+
+    /**
+     * @param theOutputDirectory
+     *            The outputDirectory to set.
+     */
+    public void setOutputDirectory( File theOutputDirectory )
+    {
+        this.outputDirectory = theOutputDirectory;
+    }
+
+    /**
+     * @return Returns the overWriteIfNewer.
+     */
+    public boolean isOverWriteIfNewer()
+    {
+        return this.overWriteIfNewer;
+    }
+
+    /**
+     * @param theOverWriteIfNewer
+     *            The overWriteIfNewer to set.
+     */
+    public void setOverWriteIfNewer( boolean theOverWriteIfNewer )
+    {
+        this.overWriteIfNewer = theOverWriteIfNewer;
+    }
+
+    /**
+     * @return Returns the overWriteReleases.
+     */
+    public boolean isOverWriteReleases()
+    {
+        return this.overWriteReleases;
+    }
+
+    /**
+     * @param theOverWriteReleases
+     *            The overWriteReleases to set.
+     */
+    public void setOverWriteReleases( boolean theOverWriteReleases )
+    {
+        this.overWriteReleases = theOverWriteReleases;
+    }
+
+    /**
+     * @return Returns the overWriteSnapshots.
+     */
+    public boolean isOverWriteSnapshots()
+    {
+        return this.overWriteSnapshots;
+    }
+
+    /**
+     * @param theOverWriteSnapshots
+     *            The overWriteSnapshots to set.
+     */
+    public void setOverWriteSnapshots( boolean theOverWriteSnapshots )
+    {
+        this.overWriteSnapshots = theOverWriteSnapshots;
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/ArtifactItem.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/ArtifactItem.java
new file mode 100644
index 0000000..2c1ae24
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/ArtifactItem.java
@@ -0,0 +1,361 @@
+/*
+ *  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.unpack;
+
+import java.io.File;
+
+import org.apache.maven.artifact.Artifact;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * ArtifactItem represents information specified in the plugin configuration
+ * section for each artifact.
+ * 
+ * @since 1.0
+ * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @version $Id$
+ */
+public class ArtifactItem extends org.apache.maven.plugin.dependency.fromConfiguration.ArtifactItem
+{
+    /**
+     * Group Id of Artifact
+     * 
+     * @parameter
+     * @required
+     */
+    private String groupId;
+
+    /**
+     * Name of Artifact
+     * 
+     * @parameter
+     * @required
+     */
+    private String artifactId;
+
+    /**
+     * Version of Artifact
+     * 
+     * @parameter
+     */
+    private String version = null;
+
+    /**
+     * Type of Artifact (War,Jar,etc)
+     * 
+     * @parameter
+     * @required
+     */
+    private String type = "jar";
+
+    /**
+     * Classifier for Artifact (tests,sources,etc)
+     * 
+     * @parameter
+     */
+    private String classifier;
+
+    /**
+     * Location to use for this Artifact. Overrides default location.
+     * 
+     * @parameter
+     */
+    private File outputDirectory;
+
+    /**
+     * Provides ability to change destination file name
+     * 
+     * @parameter
+     */
+    private String destFileName;
+
+    /**
+     * Force Overwrite..this is the one to set in pom
+     */
+    private String overWrite;
+
+    /**
+     * Force Overwrite
+     */
+    private boolean needsProcessing;
+
+    /**
+     * Artifact Item
+     */
+    private Artifact artifact;
+    
+    /**
+     * A comma separated list of file patterns to include when unpacking the
+     * artifact.
+     */
+    private String includes;
+
+    /**
+     * A comma separated list of file patterns to exclude when unpacking the
+     * artifact.
+     */
+    private String excludes;
+
+    public ArtifactItem()
+    {
+        // default constructor
+    }
+
+    public ArtifactItem( Artifact artifact )
+    {
+        this.setArtifact( artifact );
+        this.setArtifactId( artifact.getArtifactId() );
+        this.setClassifier( artifact.getClassifier() );
+        this.setGroupId( artifact.getGroupId() );
+        this.setType( artifact.getType() );
+        this.setVersion( artifact.getVersion() );
+    }
+
+    private String filterEmptyString( String in )
+    {
+        if ( in == null || in.equals( "" ) )
+        {
+            return null;
+        }
+        else
+        {
+            return in;
+        }
+    }
+
+    /**
+     * @return Returns the artifactId.
+     */
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    /**
+     * @param artifactId
+     *            The artifactId to set.
+     */
+    public void setArtifactId( String artifact )
+    {
+        this.artifactId = filterEmptyString( artifact );
+    }
+
+    /**
+     * @return Returns the groupId.
+     */
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    /**
+     * @param groupId
+     *            The groupId to set.
+     */
+    public void setGroupId( String groupId )
+    {
+        this.groupId = filterEmptyString( groupId );
+    }
+
+    /**
+     * @return Returns the type.
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+    /**
+     * @param type
+     *            The type to set.
+     */
+    public void setType( String type )
+    {
+        this.type = filterEmptyString( type );
+    }
+
+    /**
+     * @return Returns the version.
+     */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * @param version
+     *            The version to set.
+     */
+    public void setVersion( String version )
+    {
+        this.version = filterEmptyString( version );
+    }
+
+    /**
+     * @return Classifier.
+     */
+    public String getClassifier()
+    {
+        return classifier;
+    }
+
+    /**
+     * @param classifier
+     *            Classifier.
+     */
+    public void setClassifier( String classifier )
+    {
+        this.classifier = filterEmptyString( classifier );
+    }
+
+    public String toString()
+    {
+        if ( this.classifier == null )
+        {
+            return groupId + ":" + artifactId + ":" + StringUtils.defaultString( version, "?" ) + ":" + type;
+        }
+        else
+        {
+            return groupId + ":" + artifactId + ":" + classifier + ":" + StringUtils.defaultString( version, "?" )
+                + ":" + type;
+        }
+    }
+
+    /**
+     * @return Returns the location.
+     */
+    public File getOutputDirectory()
+    {
+        return outputDirectory;
+    }
+
+    /**
+     * @param location
+     *            The location to set.
+     */
+    public void setOutputDirectory( File outputDirectory )
+    {
+        this.outputDirectory = outputDirectory;
+    }
+
+    /**
+     * @return Returns the location.
+     */
+    public String getDestFileName()
+    {
+        return destFileName;
+    }
+
+    /**
+     * @param destFileName
+     *            The destFileName to set.
+     */
+    public void setDestFileName( String destFileName )
+    {
+        this.destFileName = filterEmptyString( destFileName );
+    }
+
+    /**
+     * @return Returns the needsProcessing.
+     */
+    public boolean isNeedsProcessing()
+    {
+        return this.needsProcessing;
+    }
+
+    /**
+     * @param needsProcessing
+     *            The needsProcessing to set.
+     */
+    public void setNeedsProcessing( boolean needsProcessing )
+    {
+        this.needsProcessing = needsProcessing;
+    }
+
+    /**
+     * @return Returns the overWriteSnapshots.
+     */
+    public String getOverWrite()
+    {
+        return this.overWrite;
+    }
+
+    /**
+     * @param overWriteSnapshots
+     *            The overWriteSnapshots to set.
+     */
+    public void setOverWrite( String overWrite )
+    {
+        this.overWrite = overWrite;
+    }
+
+    /**
+     * @return Returns the artifact.
+     */
+    public Artifact getArtifact()
+    {
+        return this.artifact;
+    }
+
+    /**
+     * @param artifact
+     *            The artifact to set.
+     */
+    public void setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+    }
+    
+    /**
+     * @return Returns a comma separated list of excluded items
+     */
+    public String getExcludes ()
+    {
+        return this.excludes;
+    }
+    
+    /**
+     * @param excludes 
+     *             A comma seperated list of items to exclude 
+     *             i.e.  **\/*.xml, **\/*.properties
+     */
+    public void setExcludes ( String excludes )
+    {
+        this.excludes = excludes;
+    }
+    
+    /**
+     * @return Returns a comma seperated list of included items
+     */
+    public String getIncludes()
+    {
+        return this.includes;
+    }
+
+    /**
+     * @param includes
+     *             A comma seperated list of items to inmclude 
+     *             i.e.  **\/*.xml, **\/*.properties
+     */
+    public void setIncludes ( String includes )
+    {
+        this.includes = includes;
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java
new file mode 100644
index 0000000..798e421
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java
@@ -0,0 +1,469 @@
+/*
+ *  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.unpack;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.dependency.utils.filters.ArtifactItemFilter;
+import org.apache.maven.plugin.dependency.utils.filters.MarkerFileFilter;
+import org.apache.maven.plugin.dependency.utils.markers.MarkerHandler;
+import org.apache.maven.plugin.dependency.utils.markers.UnpackFileMarkerHandler;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.codehaus.plexus.util.StringUtils;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
+
+/**
+ * Goal that retrieves a list of artifacts from the repository and unpacks them
+ * in a defined location.
+ * 
+ * This mojo reutilize org.apache.maven.plugin.dependency.fromConfiguration.UnpackMojo
+ * from maven-dependency-plugin.
+ * 
+ * The idea of this plugin, instead just unpack a list of artifacts is add some new 
+ * features necessary to make easier maintain 1.1 and 1.2 code on myfaces projects like
+ * tomahawk.
+ * 
+ * This plugin works as unpack goal of maven-dependency-plugin with 2 additional 
+ * enhancements:
+ * 
+ * 1. If some file exists on the base directories, it is added as excluded, so it is
+ * not copied to the output directory. This makes easier to manage the code and maintain it.
+ * 2. If a file is generated from the model (reading the myfaces-metadata.xml) it is not
+ * copied, since this should be generated again.
+ * 
+ * 
+<execution>
+<id>unpack-tomahawk</id>
+<phase>process-resources</phase>
+<goals>
+  <goal>unpack</goal>
+</goals>
+<configuration>
+  <artifactItems>
+    <artifactItem>
+      <groupId>org.apache.myfaces.tomahawk</groupId>
+      <artifactId>tomahawk</artifactId>
+      <version>1.1.7-SNAPSHOT</version>
+      <!-- 
+      <groupId>org.apache.myfaces.core</groupId>                   
+      <artifactId>myfaces-api</artifactId>
+      <version>1.1.6-SNAPSHOT</version>
+       -->
+      <classifier>sources</classifier>                   
+      <outputDirectory>${basedir}/target/unpackmyfaces</outputDirectory>
+    </artifactItem>
+  </artifactItems>
+</configuration>
+</execution>
+ 
+ * @since 1.0
+ * @goal unpack
+ * @phase process-sources
+ * @author Leonardo Uribe
+ * @version $Id$
+ */
+public class UnpackMojo extends AbstractFromConfigurationMojo
+{
+    /**
+     * Directory where he should check if a file exists or not. If 
+     * exists, he does not copy to , if not he copy it to the output
+     * directory.
+     * 
+     * This is possible because all files on this directory are added
+     * as excluded param.
+     * 
+     * @parameter expression="src/main/java"
+     */
+    private File baseDirectory1;
+    
+    /**
+     * Directory where he should check if a file exists or not. If 
+     * exists, he does not copy to , if not he copy it to the output
+     * directory.
+     * 
+     * This is possible because all files on this directory are added
+     * as excluded param.
+     * 
+     * @parameter 
+     */    
+    private File baseDirectory2;
+        
+    /**
+     * If the plugin should scan the model
+     * 
+     * @optional
+     * @parameter expression="${scanModel}"
+     *            default-value="false"
+     */    
+    private boolean scanModel;
+    
+    /**
+     * Directory to store flag files after unpack
+     * 
+     * @parameter expression="${project.build.directory}/dependency-maven-plugin-markers"
+     */
+    private File markersDirectory;
+    
+    /**
+     * A comma separated list of file patterns to include when unpacking the
+     * artifact.  i.e.  **\/*.xml,**\/*.properties
+     *  @since 2.0-alpha-5
+     * @parameter expression="${mdep.unpack.includes}"
+     */
+    private String includes;
+
+    /**
+     * A comma separated list of file patterns to exclude when unpacking the
+     * artifact.  i.e.  **\/*.xml,**\/*.properties
+     * @since 2.0-alpha-5
+     * @parameter expression="${mdep.unpack.excludes}"
+     */
+    private String excludes;
+
+    /**
+     * Main entry into mojo. This method gets the ArtifactItems and iterates
+     * through each one passing it to unpackArtifact.
+     * 
+     * @throws MojoExecutionException
+     *             with a message if an error occurs.
+     * 
+     * @see ArtifactItem
+     * @see #getArtifactItems
+     * @see #unpackArtifact(ArtifactItem)
+     */
+    public void execute()
+        throws MojoExecutionException
+    {
+        String existingFiles = scanAndAddExistingFilesAsExcluded(
+                baseDirectory1, baseDirectory2);
+        
+        String excludedFiles = null;
+        
+        ArrayList processedItems = getProcessedArtifactItems( false );
+        Iterator iter = processedItems.iterator();
+        while ( iter.hasNext() )
+        {
+            ArtifactItem artifactItem = (ArtifactItem) iter.next();
+            
+            if ( artifactItem.isNeedsProcessing() )
+            {
+                if (scanModel)
+                {
+                    String generatedFiles = this.scanModelAndAddGeneratedFiles(artifactItem);                    
+                    excludedFiles = existingFiles + ','+ generatedFiles;
+                }
+                else
+                {
+                    excludedFiles = existingFiles;
+                }
+                
+                //Exclude existing files on baseDirectory1 and baseDirectory2
+                if (artifactItem.getExcludes() != null)
+                {
+                    artifactItem.setExcludes(artifactItem.getExcludes()+','+excludedFiles);
+                }
+                else
+                {
+                    artifactItem.setExcludes(excludedFiles);
+                }
+                //Unpack
+                unpackArtifact( artifactItem );
+            }
+            else
+            {
+                this.getLog().info( artifactItem.getArtifact().getFile().getName() + " already unpacked." );
+            }
+        }
+    }
+
+    /**
+     * This method gets the Artifact object and calls DependencyUtil.unpackFile.
+     * 
+     * @param artifactItem
+     *            containing the information about the Artifact to unpack.
+     * 
+     * @throws MojoExecutionException
+     *             with a message if an error occurs.
+     * 
+     * @see #getArtifact
+     * @see DependencyUtil#unpackFile(Artifact, File, File, ArchiverManager,
+     *      Log)
+     */
+    private void unpackArtifact( ArtifactItem artifactItem )
+        throws MojoExecutionException
+    {
+        MarkerHandler handler = new UnpackFileMarkerHandler( artifactItem, this.markersDirectory );
+        
+        unpack(
+                artifactItem.getArtifact().getFile(),
+                artifactItem.getOutputDirectory(),
+                artifactItem.getIncludes(),
+                artifactItem.getExcludes());
+        handler.setMarker();
+    }
+
+    ArtifactItemFilter getMarkedArtifactFilter( ArtifactItem item )
+    {
+        MarkerHandler handler = new UnpackFileMarkerHandler( item, this.markersDirectory );
+
+        return new MarkerFileFilter( this.isOverWriteReleases(), this.isOverWriteSnapshots(),
+                                     this.isOverWriteIfNewer(), handler );
+    }
+    
+    protected ArrayList getProcessedArtifactItems(boolean removeVersion)
+        throws MojoExecutionException 
+    {
+        ArrayList items = super.getProcessedArtifactItems( removeVersion );
+        Iterator iter = items.iterator();
+        while ( iter.hasNext() )
+        {
+            ArtifactItem artifactItem = (ArtifactItem) iter.next();
+            if ( StringUtils.isEmpty(artifactItem.getIncludes()) )
+            {
+                artifactItem.setIncludes( getIncludes() );
+            }
+            if ( StringUtils.isEmpty(artifactItem.getExcludes()) )
+            {
+                artifactItem.setExcludes( getExcludes() );
+            }
+        }
+        return items;
+    }
+    
+    protected String scanModelAndAddGeneratedFiles(ArtifactItem artifactItem)
+        throws MojoExecutionException
+    {
+        
+        ArrayList exclusions = new ArrayList();
+        
+        Model model = IOUtils.getModelFromArtifact(artifactItem.getArtifact());
+        
+        if (model != null)
+        {
+            for (Iterator it = model.components(); it.hasNext();)
+            {
+                ComponentMeta component = (ComponentMeta) it.next();
+
+                if (component.getModelId().equals(model.getModelId()))
+                {
+                    if (component.isGeneratedComponentClass().booleanValue())
+                    {
+                        getLog().info("Adding Generated: "+ component.getClassName());
+                        exclusions.add(StringUtils.replace(
+                                component.getClassName(), ".", "/")
+                                + ".java");
+                    }
+                    if (component.isGeneratedTagClass().booleanValue())
+                    {
+                        getLog().info("Adding Generated: "+ component.getTagClass());
+                        exclusions.add(StringUtils.replace(component.getTagClass(),
+                                ".", "/")
+                                + ".java");
+                    }                
+                }
+            }
+            for (Iterator it = model.converters(); it.hasNext();)
+            {
+                ConverterMeta converter = (ConverterMeta) it.next();
+
+                if (converter.getModelId().equals(model.getModelId()))
+                {
+                    if (converter.isGeneratedTagClass().booleanValue())
+                    {
+                        getLog().info("Adding Generated: "+ converter.getTagClass());
+                        exclusions.add(StringUtils.replace(converter.getTagClass(),
+                                ".", "/")
+                                + ".java");
+                    }                
+                }
+            }
+            for (Iterator it = model.validators(); it.hasNext();)
+            {
+                ValidatorMeta validator = (ValidatorMeta) it.next();
+
+                if (validator.getModelId().equals(model.getModelId()))
+                {
+                    if (validator.isGeneratedComponentClass().booleanValue())
+                    {
+                        getLog().info("Adding Generated: "+ validator.getClassName());
+                        exclusions.add(StringUtils.replace(
+                                validator.getClassName(), ".", "/")
+                                + ".java");
+                    }
+                    if (validator.isGeneratedTagClass().booleanValue())
+                    {
+                        getLog().info("Adding Generated: "+ validator.getTagClass());
+                        exclusions.add(StringUtils.replace(validator.getTagClass(),
+                                ".", "/")
+                                + ".java");
+                    }                
+                }
+            }
+            
+        }
+        else
+        {
+            getLog().info("No myfaces-metadata.xml found on artifact.");
+        }
+
+        StringBuilder existingFiles = new StringBuilder();
+        for (int i = 0; i < exclusions.size(); i++)
+        {
+            existingFiles.append(exclusions.get(i));
+            if (i != exclusions.size() - 1)
+            {
+                existingFiles.append(',');
+            }
+        }
+        
+        return existingFiles.toString();
+    }
+    
+    /**
+     * This method scan on both directories and add all files as excluded files to be 
+     * unpacked. Return the resulting filter.
+     * 
+     * @param exclusions
+     * @param dir1
+     * @param dir2
+     * @return
+     */
+    protected String scanAndAddExistingFilesAsExcluded(File dir1, File dir2)
+    {
+        ArrayList exclusions = new ArrayList();
+        
+        if (dir1 != null)
+        {
+            addExcludes(dir1.getPath(), dir1, exclusions);
+        }
+        
+        if (dir2 != null)
+        {
+            addExcludes(dir2.getPath(), dir2, exclusions);
+        }
+        
+        StringBuilder existingFiles = new StringBuilder();
+        for (int i = 0; i < exclusions.size(); i++)
+        {
+            existingFiles.append(exclusions.get(i));
+            if (i != exclusions.size() - 1)
+            {
+                existingFiles.append(',');
+            }
+        }
+        
+        return existingFiles.toString();
+    }
+    
+    protected void addExcludes(String basePath, File f, List exclusions)
+    {
+        
+        if ( f.isDirectory() )
+        {
+            File [] fileList = f.listFiles();
+
+            for (int i = 0; i < fileList.length; ++i)
+            {
+                if (!fileList[i].getName().equals(".svn"))
+                {
+                    addExcludes(basePath,fileList[i], exclusions);
+                }
+            }
+        }
+        else
+        {
+            String path = f.getPath();
+            path = path.replace(basePath,"");
+            while (path.startsWith("/"))
+            {
+                path = path.substring(1);
+            }
+            while (path.startsWith("\\"))
+            {
+                path = path.substring(1);
+            }
+            path = StringUtils.replace( path, "\\", "/" );
+            exclusions.add(path);
+            getLog().info("Adding: "+path);
+        }        
+    }
+
+    /**
+     * @return Returns the markersDirectory.
+     */
+    public File getMarkersDirectory()
+    {
+        return this.markersDirectory;
+    }
+
+    /**
+     * @param theMarkersDirectory
+     *            The markersDirectory to set.
+     */
+    public void setMarkersDirectory( File theMarkersDirectory )
+    {
+        this.markersDirectory = theMarkersDirectory;
+    }
+    
+   
+    /**
+     * @return Returns a comma separated list of excluded items
+     */
+    public String getExcludes ()
+    {
+        return this.excludes;
+    }
+    
+    /**
+     * @param excludes 
+     *          A comma separated list of items to exclude 
+     *          i.e.  **\/*.xml, **\/*.properties
+     */
+    public void setExcludes ( String excludes )
+    {
+        this.excludes = excludes;
+    }
+    
+    /**
+     * @return Returns a comma separated list of included items
+     */
+    public String getIncludes()
+    {
+        return this.includes;
+    }
+
+    /**
+     * @param includes
+     *          A comma separated list of items to include 
+     *          i.e.  **\/*.xml, **\/*.properties
+     */
+    public void setIncludes ( String includes )
+    {
+        this.includes = includes;
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/BuildException.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/BuildException.java
new file mode 100644
index 0000000..2f0c682
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/BuildException.java
@@ -0,0 +1,41 @@
+/*
+ *  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.utils;
+
+
+/**
+ * An unchecked exception that can be thrown whenever something goes wrong.
+ * <p>
+ * An unchecked exception is useful in this particular application because
+ * we don't need to bother declaring it everywhere. Checked exceptions are
+ * fine here because there is no sensible "recovery strategy" for a build
+ * failure except terminating the build.
+ */
+public class BuildException extends RuntimeException
+{
+    public BuildException(String msg)
+    {
+        super(msg);
+    }
+    
+    public BuildException(String msg, Exception cause)
+    {
+        super(msg, cause);
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/ConsoleLogSystem.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/ConsoleLogSystem.java
new file mode 100644
index 0000000..1cc61db
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/ConsoleLogSystem.java
@@ -0,0 +1,76 @@
+/*
+ *  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.utils;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.log.LogChute;
+
+public class ConsoleLogSystem implements LogChute
+{
+
+    final Logger log = Logger.getLogger(ConsoleLogSystem.class.getName());
+    
+    public Logger getLogger()
+    {
+        return log;
+    }
+    
+    public void init(RuntimeServices runtimeservices) throws Exception
+    {
+        return;
+    }
+
+    public boolean isLevelEnabled(int i)
+    {
+        return true;
+    }
+
+    public void log(int level, String message)
+    {
+        switch ( level )
+        {
+            case LogChute.WARN_ID:
+                getLogger().log(Level.WARNING, message );
+                break;
+            case LogChute.INFO_ID:
+                // velocity info messages are too verbose, just consider them as debug messages...
+                getLogger().log(Level.INFO, message );
+                break;
+            case LogChute.DEBUG_ID:
+                getLogger().log(Level.FINE, message );
+                break;
+            case LogChute.ERROR_ID:
+                getLogger().log(Level.SEVERE, message );
+                break;
+            default:
+                getLogger().log(Level.ALL, message );
+                break;
+        }        
+    }
+
+    public void log(int level, String message, Throwable throwable)
+    {
+        log(level,message);
+        throw new RuntimeException(throwable);
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/MyfacesUtils.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/MyfacesUtils.java
new file mode 100644
index 0000000..17a435d
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/MyfacesUtils.java
@@ -0,0 +1,745 @@
+/*
+ *  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.utils;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.MethodSignatureMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyMeta;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyHolder;
+
+/**
+ * Collection of useful utility methods.
+ * <p>
+ * An instance of this type is made available to the templates used to generate
+ * output files, so that they can call these useful methods.
+ */
+public class MyfacesUtils
+{
+    public MyfacesUtils()
+    {
+    }
+
+    public static String getPrefixedPropertyName(String prefix,
+            String propertyName)
+    {
+        return prefix + Character.toUpperCase(propertyName.charAt(0))
+                + propertyName.substring(1);
+    }
+    
+    /**
+     * Convert h:commandButton to commandButton
+     * 
+     * @param prefixedName
+     * @return
+     */
+    public static String getTagName(String prefixedName)
+    {
+        return prefixedName.substring(prefixedName.indexOf(':')+1); 
+    }
+    
+    public static String getTagPrefix(String prefixedName)
+    {
+        return prefixedName.substring(0,prefixedName.indexOf(':'));
+    }
+
+    public static String getJspPropertyType11(PropertyMeta property)
+    {
+//        if (property.isMethodExpression())
+//            return "MethodBinding";
+
+//        if (property.isMethodBinding())
+//            return "MethodBinding";
+        //On 1.1 all properties is mapped as String
+        return "String";
+    }
+    
+    public static String getFullJspPropertyType11(PropertyMeta property)
+    {
+        if (property.isMethodExpression())
+        {
+            return "javax.faces.el.MethodBinding";
+        }
+
+        if (property.isMethodBinding())
+        {
+            return "javax.faces.el.MethodBinding";
+        }
+
+        return "java.lang.String";
+    }
+    
+
+    public static String getJspPropertyType12(PropertyMeta property)
+    {
+        if (property.getJspName().equals("actionListener"))
+        {
+            return "javax.el.MethodExpression";
+        }
+        if (property.getJspName().equals("validator"))
+        {
+            return "javax.el.MethodExpression";
+        }
+        if (property.getJspName().equals("valueChangeListener"))
+        {
+            return "javax.el.MethodExpression";
+        }
+        
+        if (property.isMethodExpression())
+        {
+            return "MethodExpression";
+        }
+
+        if (property.isMethodBinding())
+        {
+            return "MethodBinding";
+        }
+
+        if (!property.isLiteralOnly().booleanValue())
+        {
+            return "ValueExpression";
+        }
+        else
+        {
+            return property.getClassName();
+        }
+    }
+
+    public static String getVariableFromName(String name)
+    {
+        if (name == null)
+        {
+            return null;
+        }
+
+        if (RESERVED_WORDS.contains(name))
+        {
+            name = name + "Param";
+        }
+
+        return name;
+    }
+
+    // TODO: perhaps this could just return a list of class names for
+    // templates to iterate over, rather than building the text itself?
+    //
+    // TODO: why are we importing tag classes into components anyway?
+    public static String importTagClasses(PropertyHolder component)
+    {
+        Set imports = new HashSet();
+        for (Iterator it = component.properties(); it.hasNext();)
+        {
+            PropertyMeta property = (PropertyMeta) it.next();
+            if (property.getClassName() != null && 
+                    !PRIMITIVE_TYPES.contains(property.getClassName()))
+            {
+                if (!property.getClassName().startsWith("java.lang"))
+                {
+                    imports.add(property.getClassName());
+                }
+            }
+        }
+
+        StringBuilder value = new StringBuilder();
+
+        for (Iterator importIterator = imports.iterator(); importIterator
+                .hasNext();)
+        {
+            value.append("import ");
+            value.append((String) importIterator.next());
+            value.append(';');
+            value.append('\n');
+        }
+
+        return value.toString();
+    }
+    
+    public static String importTagClasses12(ComponentMeta component)
+    {
+        Set imports = new HashSet();
+        for (Iterator it = component.properties(); it.hasNext();)
+        {
+            PropertyMeta property = (PropertyMeta) it.next();
+            if (property.getClassName() != null && 
+                    !PRIMITIVE_TYPES.contains(property.getClassName()))
+            {
+                if (!property.getClassName().startsWith("java.lang"))
+                {
+                    imports.add(property.getClassName());
+                }
+            }
+            if (property.getJspName().equals("actionListener"))
+            {
+                imports.add("javax.faces.event.MethodExpressionActionListener");
+            }
+            if (property.getJspName().equals("valueChangeListener"))
+            {
+                imports.add("javax.faces.event.MethodExpressionValueChangeListener");
+            }
+            if (property.getJspName().equals("validator"))
+            {
+                imports.add("javax.faces.validator.MethodExpressionValidator");
+            }
+        }
+
+        StringBuilder value = new StringBuilder();
+
+        for (Iterator importIterator = imports.iterator(); importIterator
+                .hasNext();)
+        {
+            value.append("import ");
+            value.append((String) importIterator.next());
+            value.append(';');
+            value.append('\n');
+        }
+
+        return value.toString();
+    }
+    
+
+    public static boolean isConverter(String propClass)
+    {
+        return ("javax.faces.convert.Converter".equals(propClass));
+    }
+    
+    public static boolean isList(String propClass)
+    {
+        if (propClass == null)
+        {
+            return false;
+        }
+        else if(propClass.contains("List"))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    public static String castIfNecessary(String propClass)
+    {
+      if (propClass.equals("Object") || propClass.equals("java.lang.Object"))
+      {
+        return "";
+      }
+
+      if (isPrimitiveClass(propClass))
+      {
+        propClass = getBoxedClass(propClass);
+      }
+
+      return "(" + propClass + ")";
+    }    
+        
+    public static String getBoxedClass(String className)
+    {
+        if ("boolean".equals(className))
+        {
+            return "Boolean";
+        }
+        else if ("byte".equals(className))
+        {
+            return "Byte";
+        }
+        else if ("char".equals(className))
+        {
+            return "Character";
+        }
+        else if ("double".equals(className))
+        {
+            return "Double";
+        }
+        else if ("float".equals(className))
+        {
+            return "Float";
+        }
+        else if ("int".equals(className))
+        {
+            return "Integer";
+        }
+        else if ("long".equals(className))
+        {
+            return "Long";
+        }
+        else if ("short".equals(className))
+        {
+            return "Short";
+        }
+        else
+        {
+            return className;
+        }
+    }
+    
+    public static String getSignatureParams(MethodSignatureMeta signature)
+    {
+        String[] paramTypes = (signature != null) ? signature.getParameterTypes() : null;
+
+        String classArray;
+
+        if (paramTypes == null || paramTypes.length == 0)
+        {
+          classArray = "new Class[0]";
+        }
+        else
+        {
+          StringBuffer sb = new StringBuffer();
+          sb.append("new Class[]{");
+          for (int i = 0; i < paramTypes.length; i++)
+          {
+            if (i > 0)
+            {
+              sb.append(',');
+            }
+            sb.append(paramTypes[i]);
+            sb.append(".class");
+          }
+
+          // TODO: remove trailing comma
+          sb.append(',');
+
+          sb.append('}');
+          classArray = sb.toString();
+        }
+        return classArray;
+    }
+    
+    public static boolean isStringMethodBindingReturnType(MethodSignatureMeta sig)
+    {
+        return (sig != null && "java.lang.String".equals(sig.getReturnType()));
+    }
+    
+    static public String getMethodReaderFromProperty(String propertyName,
+            String propertyClass)
+    {
+        String methodPrefix = ("boolean".equals(propertyClass) ? "is" : "get");
+        return getPrefixedPropertyName(methodPrefix, propertyName);
+    }
+    
+    public static String getPrimitiveType(String className)
+    {
+        if (className.startsWith("java.lang."))
+        {
+            className = className.replace("java.lang.", "");
+        }
+
+        if (className.endsWith("eger"))
+        {
+            className = className.replace("eger", "");
+        }
+
+        if (MyfacesUtils.isPrimitiveClass(className.toLowerCase()))
+        {
+            return className.toLowerCase();
+        }
+        else
+        {
+            return className;
+        }
+    }    
+    
+    public static boolean isPrimitiveClass(String className)
+    {
+        return "boolean".equals(className) || "byte".equals(className)
+                || "char".equals(className) || "double".equals(className)
+                || "float".equals(className) || "int".equals(className)
+                || "long".equals(className) || "short".equals(className);
+    }
+
+    private static Set _createPrimitiveTypesSet()
+    {
+        Set primitives = new TreeSet();
+        for (int i = 0; i < _PRIMITIVE_TYPES.length; i++)
+        {
+            String type = _PRIMITIVE_TYPES[i];
+            primitives.add(type);
+            primitives.add(type + "[]");
+        }
+        return Collections.unmodifiableSet(primitives);
+    }
+
+    private static Set _createReservedWordsSet()
+    {
+        Set reserved = new TreeSet();
+        for (int i = 0; i < _RESERVED_WORDS.length; i++)
+        {
+            String keyword = _RESERVED_WORDS[i];
+            reserved.add(keyword);
+        }
+        return Collections.unmodifiableSet(reserved);
+    }
+
+    static private final String[] _PRIMITIVE_TYPES = new String[] {
+        // TODO: Shouldn't java.lang.* be specified in that list as well?
+    "boolean", "byte", "char", "float", "double", "int", "short", "long", };
+
+    static private final String[] _RESERVED_WORDS = new String[] { "abstract",
+            "assert", "boolean", "break", "byte", "case", "catch", "char",
+            "class", "const", "continue", "default", "do", "double", "else",
+            "extends", "final", "finally", "float", "for", "goto", "if",
+            "implements", "import", "instanceof", "int", "interface", "long",
+            "native", "new", "package", "private", "protected", "public",
+            "return", "short", "static", "super", "switch", "synchronized",
+            "this", "throw", "throws", "transient", "try", "void", "volatile",
+            "while", };
+
+    static public final Set RESERVED_WORDS = _createReservedWordsSet();
+    static public final Set PRIMITIVE_TYPES = _createPrimitiveTypesSet();
+
+    static private final Pattern _GENERIC_TYPE = Pattern
+            .compile("([^<]+)<(.+)>");
+    
+    //UNUSED METHODS
+
+
+    static public String convertClassToSourcePath(String className,
+            String fileExtension)
+    {
+        return (className.replace('.', File.separatorChar) + fileExtension);
+    }
+
+    static public boolean isFullClass(String className)
+    {
+        return (className != null && className.indexOf('.') != -1);
+    }
+
+    /*
+    public static String getGenericsFromProperty(PropertyMeta property){
+        String gen = "";
+        for (int i = 0; i < property.getAttributeClassParameters().length; i++) {
+            if (i>0){
+                gen += ",";
+            }
+            gen += getClassFromFullClass(property.getAttributeClassParameters()[i]);          
+        }
+        return (gen.length() > 0?"<"+gen+">":gen);
+    }
+    */
+
+    /**
+     * Extract the simple class name from a fully-qualified classname.
+     * <p>
+     * Given a string like "org.apache.Foo", this method returns "Foo".
+     */
+    static public String getClassFromFullClass(String fullClass)
+    {
+        if (fullClass == null)
+        {
+            return null;
+        }
+
+        int lastSep = fullClass.lastIndexOf('.');
+        // Note: this code also works for the empty package
+        return (fullClass.substring(lastSep + 1));
+    }
+
+    static public String getPackageFromFullClass(String fullClass)
+    {
+        if (fullClass == null)
+        {
+            return null;
+        }
+
+        int lastSep = fullClass.lastIndexOf('.');
+
+        // detect the empty package
+        if (lastSep == -1)
+        {
+            return "";
+        }
+
+        return (fullClass.substring(0, lastSep));
+    }
+
+    static public String getConstantNameFromProperty(String propertyName)
+    {
+        return getConstantNameFromProperty(propertyName, null);
+    }
+
+    static public String getConstantNameFromProperty(String propertyName,
+            String constantSuffix)
+    {
+        StringBuffer constantName = new StringBuffer();
+
+        for (int i = 0; i < propertyName.length(); i++)
+        {
+            char ch = propertyName.charAt(i);
+            if (i > 0 && Character.isUpperCase(ch)
+                    && Character.isLowerCase(propertyName.charAt(i - 1)))
+            {
+                constantName.append('_');
+            }
+            ch = Character.toUpperCase(ch);
+            constantName.append(ch);
+        }
+
+        if (constantSuffix != null)
+        {
+            constantName.append(constantSuffix);
+        }
+
+        return constantName.toString();
+    }
+
+    static public String getPropertyClass(PropertyMeta property)
+    {
+        String propertyFullClass = property.getClassName();
+        String propertyClass = MyfacesUtils
+                .getClassFromFullClass(propertyFullClass);
+        /*
+        String[] genericTypes = property.getPropertyClassParameters();
+        if(genericTypes != null && genericTypes.length > 0)
+        {
+          StringBuffer buffer = new StringBuffer(60);
+          buffer.append(propertyClass);
+          buffer.append('<');
+          int max = genericTypes.length - 1;
+          for(int i = 0; i <= max; i++)
+          {
+            _buildPropertyClass(buffer, genericTypes[i]);
+            if(i < max)
+            {
+              buffer.append(", ");
+            }
+          }
+          buffer.append('>');
+          
+          propertyClass = buffer.toString();
+        }*/
+
+        return propertyClass;
+    }
+
+    static public String getMethodNameFromEvent(String methodPrefix,
+            String eventName, String methodSuffix)
+    {
+        return methodPrefix + Character.toUpperCase(eventName.charAt(0))
+                + eventName.substring(1) + methodSuffix;
+    }
+
+    static public String getEventNameFromEventType(String eventFullClass)
+    {
+        String eventName = getClassFromFullClass(eventFullClass);
+        return Character.toLowerCase(eventName.charAt(0))
+                + eventName.substring(1, eventName.length());
+    }
+    
+    /*
+    static public String getAlternatePropertyClass(PropertyMeta property)
+    {
+      StringBuffer buffer = new StringBuffer(60);
+      _buildPropertyClass(buffer, property.getAlternateClass());
+      
+      return buffer.toString();
+    }
+    */
+
+    static public String primitiveDefaultValue(String className)
+    {
+        if ("boolean".equals(className))
+        {
+            return "false";
+        }
+        else if ("byte".equals(className))
+        {
+            return "0";
+        }
+        else if ("char".equals(className))
+        {
+            return "''";
+        }
+        else if ("double".equals(className))
+        {
+            return "0.0d";
+        }
+        else if ("float".equals(className))
+        {
+            return "0.0f";
+        }
+        else if ("int".equals(className))
+        {
+            return "0";
+        }
+        else if ("long".equals(className))
+        {
+            return "0L";
+        }
+        else if ("short".equals(className))
+        {
+            return "0";
+        }
+        else
+        {
+            return className;
+        }
+    }
+
+    static public String fill(String base, int length)
+    {
+        if (base == null || base.length() > length)
+        {
+            return base;
+        }
+
+        StringBuffer filled = new StringBuffer(base);
+        for (int i = base.length(); i < length; i++)
+        {
+            filled.append(' ');
+        }
+        return filled.toString();
+    }
+
+    static public String getVariableFromClass(String className)
+    {
+        if (className == null)
+        {
+            return null;
+        }
+
+        for (int i = 0; i < className.length(); i++)
+        {
+            char ch = className.charAt(i);
+            if (Character.isLowerCase(ch))
+            {
+                if (i > 0)
+                {
+                    return Character.toLowerCase(className.charAt(i - 1))
+                            + className.substring(i);
+                }
+                break;
+            }
+        }
+
+        throw new IllegalStateException("Class name \"" + className
+                + "\" does not use initcaps");
+    }
+
+    static public String convertStringToLiteral(String value)
+    {
+        return convertStringToLiteral("String", value);
+    }
+
+    static public String convertStringToLiteral(String className, String value)
+    {
+        if (value == null)
+        {
+            return null;
+        }
+        else if ("String".equals(className))
+        {
+            return "\"" + value.replaceAll("\'", "\\'") + "\"";
+        }
+        else if ("Number".equals(className))
+        {
+            // Double vs. Integer.
+            if (value.indexOf(".") == -1)
+            {
+                return "Integer.valueOf(" + value + ")";
+            }
+            else
+            {
+                return "Double.valueOf(" + value + ")";
+            }
+        }
+        else
+        {
+            return value;
+        }
+    }
+
+    static public String getDefaultValue(PropertyMeta property)
+    {
+        String propertyFullClass = property.getClassName();
+        String def = property.getDefaultValue();
+        if (def == null || def.length() == 0)
+        {
+            return null;
+        }
+        if (isPrimitiveClass(propertyFullClass))
+        {
+            return def;
+        }
+        else if ("java.lang.String".equals(propertyFullClass))
+        {
+            if (def.startsWith("\"") && def.endsWith("\""))
+            {
+                return def;
+            }
+            else
+            {
+                return "\"" + def + "\"";
+            }
+        }
+        else
+        {
+            //Any other class, so we return the default value
+            return def;
+        }
+    }
+    
+    public static String getDefaultValueField(PropertyMeta property)
+    {
+        String def =  getDefaultValue(property);
+
+        if (property.getClassName().endsWith("Boolean") && def != null)
+        {
+                def = "Boolean.valueOf("+def+")";
+        }
+        return def;
+    }
+
+    static private void _buildPropertyClass(StringBuffer buffer, String type)
+    {
+        Matcher matcher = _GENERIC_TYPE.matcher(type);
+        if (matcher.matches())
+        {
+            // Generic type
+            buffer.append(MyfacesUtils.getClassFromFullClass(matcher.group(1)));
+            buffer.append('<');
+            String[] types = matcher.group(2).split(",");
+            int max = types.length - 1;
+            for (int i = 0; i <= max; i++)
+            {
+                _buildPropertyClass(buffer, types[i]);
+                if (i < max)
+                {
+                    buffer.append(", ");
+                }
+            }
+            buffer.append('>');
+        }
+        else
+        {
+            // Non-generic type
+            buffer.append(MyfacesUtils.getClassFromFullClass(type));
+        }
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/RelativeClasspathResourceLoader.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/RelativeClasspathResourceLoader.java
new file mode 100644
index 0000000..4539451
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/utils/RelativeClasspathResourceLoader.java
@@ -0,0 +1,149 @@
+/*
+ *  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.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+import org.apache.velocity.util.ClassUtils;
+import org.apache.velocity.util.ExceptionUtils;
+
+/**
+ * This class extends ClasspathResourceLoader adding the feature
+ * of configure a path inside the classpath for load resources.
+ * 
+ * @author Leonardo
+ *
+ */
+public class RelativeClasspathResourceLoader extends ResourceLoader
+{
+
+    private List paths = new ArrayList();
+
+    public void init(ExtendedProperties configuration)
+    {
+        if (log.isTraceEnabled())
+        {
+            log
+                    .trace("RelativeClasspathResourceLoader : initialization complete.");
+        }
+
+        paths.addAll(configuration.getVector("path"));
+
+        // trim spaces from all paths
+        org.apache.velocity.util.StringUtils.trimStrings(paths);
+        if (log.isInfoEnabled())
+        {
+            // this section lets tell people what paths we will be using
+            int sz = paths.size();
+            for (int i = 0; i < sz; i++)
+            {
+                log.info("RelativeClasspathResourceLoader : adding path '"
+                        + (String) paths.get(i) + "'");
+            }
+            log
+                    .trace("RelativeClasspathResourceLoader : initialization complete.");
+        }
+    }
+
+    public InputStream getResourceStream(String name)
+            throws ResourceNotFoundException
+    {
+        if (StringUtils.isEmpty(name))
+        {
+            throw new ResourceNotFoundException("No template name provided");
+        }
+
+        /**
+         * look for resource in thread classloader first (e.g. WEB-INF\lib in
+         * a servlet container) then fall back to the system classloader.
+         */
+
+        int size = paths.size();
+        for (int i = 0; i < size; i++)
+        {
+            String path = (String) paths.get(i);
+            InputStream inputStream = null;
+
+            try
+            {
+                inputStream = findTemplate(path, name);
+            }
+            catch (IOException ioe)
+            {
+                log.error("While loading Template " + name + ": ", ioe);
+            }
+
+            if (inputStream != null)
+            {
+                return inputStream;
+            }
+        }
+        String msg = "ClasspathResourceLoader Error: cannot find resource "
+                + name;
+
+        throw new ResourceNotFoundException(msg);
+    }
+
+    private InputStream findTemplate(final String path, final String name)
+            throws IOException
+    {
+        InputStream result = null;
+
+        try
+        {
+            result = ClassUtils.getResourceAsStream(getClass(), path + "/"
+                    + name);
+        }
+        catch (Exception fnfe)
+        {
+            throw (ResourceNotFoundException) ExceptionUtils.createWithCause(
+                    ResourceNotFoundException.class, "problem with template: "
+                            + name, fnfe);
+        }
+
+        if (result == null)
+        {
+            String msg = "ClasspathResourceLoader Error: cannot find resource "
+                    + name;
+
+            throw new ResourceNotFoundException(msg);
+        }
+
+        return result;
+    }
+
+    public boolean isSourceModified(Resource resource)
+    {
+        return false;
+    }
+
+    public long getLastModified(Resource resource)
+    {
+        return 0;
+    }
+
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java
new file mode 100644
index 0000000..3bf6f54
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocContentMojo.java
@@ -0,0 +1,885 @@
+/*
+ *  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.tagdoc;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.digester.AbstractObjectCreationFactory;
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.MavenReportException;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.Flattener;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ClassMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.TagMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
+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.apache.velocity.runtime.resource.ResourceManagerImpl;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+import org.codehaus.plexus.util.xml.Xpp3DomWriter;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.xml.sax.Attributes;
+
+/**
+ * 
+ * Generate the tag doc content pages using velocity. This is done before
+ * site, because maven-site-plugin use velocity and if we do this inside 
+ * report generation, we cause a ClassLoader problem.
+ * 
+ * @author Leonardo Uribe
+ * @goal tagdoc-content
+ * @phase generate-resources
+ */
+public class TagdocContentMojo extends AbstractMojo
+{
+    private Model _model;
+
+    /**
+     * Specifies the directory where the report will be generated
+     *
+     * @parameter default-value="${project.reporting.outputDirectory}"
+     * @required
+     */
+    private File outputDirectory;
+
+    /**
+     * Directory where the original site is present.
+     * (TRIED using ${baseDir}/src/site;  that inserted a 'null' into
+     * the string for some reason.  TRIED using ${siteDirectory},
+     * which was undefined.  TRIED ${project.directory}src/site; which also
+     * inserted a null.  ${project.build.directory}/../src/site seems to work,
+     * though it assumes that ${project.build.directory} is 
+     * ${project.directory}/target.
+     * 
+     * @parameter default-value="${project.build.directory}/../src/site/"
+     * @required
+     */
+    private File siteDirectory;
+
+    /**
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @parameter
+     */
+    private Map taglibs;
+        
+    /**
+     * @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";
+    
+    /**
+     * @parameter expression="src/main/resources/META-INF"
+     */
+    private File templateSourceDirectory;
+    
+    /**
+     * @parameter expression="src/main/tagdoc"
+     */    
+    private File baseFilesSourceDirectory;
+    
+    /**
+     * @parameter
+     */
+    private List modelIds;
+    
+    /**
+     * @parameter expression="xdoc-component.vm"
+     */
+    private String templateComponent;
+    
+    /**
+     * @parameter expression="xdoc-converter.vm"
+     */
+    private String templateConverter;
+    
+    /**
+     * @parameter expression="xdoc-validator.vm"
+     */
+    private String templateValidator;
+        
+    /**
+     * @parameter expression="xdoc-tag.vm"
+     */
+    private String templateTag;
+
+    static private final String _DOC_SUBDIRECTORY = "tagdoc";
+
+    public void execute() throws MojoExecutionException, MojoFailureException
+    {
+        if (modelIds == null)
+        {
+            modelIds = new ArrayList();
+            modelIds.add(project.getArtifactId());
+        }
+        
+        if (taglibs == null)
+        {
+            taglibs = new HashMap();
+            taglibs.put("t", "http://myfaces.apache.org/tomahawk");
+        }
+        
+        try
+        {
+            _model = IOUtils.loadModel(new File(buildDirectory,
+                    metadataFile));
+            new Flattener(_model).flatten();            
+            _generateTagDocs();
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Couldn't generate tagdoc", e);
+        }        
+    }
+    
+    public boolean canGenerate(ClassMeta component)
+    {
+        if ( modelIds.contains(component.getModelId()))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    public class CustomResourceManagerImpl extends ResourceManagerImpl
+    {
+        public CustomResourceManagerImpl()
+        {
+            super();
+        }
+    }
+    
+    private VelocityEngine initVelocity() throws MojoExecutionException
+    {        
+        Properties p = new Properties();
+        p.setProperty( "resource.loader", "file, class" );
+        p.setProperty( "file.resource.loader.class",
+                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+        p.setProperty( "file.resource.loader.path", templateSourceDirectory.getPath());
+        p.setProperty( "class.resource.loader.class",
+                "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.RelativeClasspathResourceLoader" );
+        p.setProperty( "class.resource.loader.path", "META-INF");                    
+        p.setProperty( "velocimacro.library", "componentClassMacros11.vm");
+        p.setProperty( "velocimacro.permissions.allow.inline","true");
+        p.setProperty( "velocimacro.permissions.allow.inline.local.scope", "true");
+        p.setProperty( "directive.foreach.counter.initial.value","0");
+        p.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+        "org.apache.myfaces.buildtools.maven2.plugin.builder.utils.ConsoleLogSystem" );
+                        
+        VelocityEngine velocityEngine = new VelocityEngine();
+                
+        try
+        {
+            velocityEngine.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error creating VelocityEngine", e);
+        }
+        
+        return velocityEngine;
+                
+    }
+            
+    private void _generateTagDocs() throws Exception
+    {
+        Model model = getModel();
+        if (model.getComponents().size() == 0)
+        {
+            getLog().info("Nothing to generate - no components found");
+            return;
+        }
+        
+        VelocityEngine velocityEngine = initVelocity();
+        
+        VelocityContext baseContext = new VelocityContext();
+        baseContext.put("utils", new MyfacesUtils());
+        baseContext.put("tagdocUtils", new TagdocUtils());
+        baseContext.put("model",getModel());
+        
+        Iterator components = model.components();
+
+        Iterator validators = model.validators();
+
+        Iterator converters = model.converters();
+        
+        Iterator tags = model.tags();
+
+        Set componentPages = new TreeSet();
+        Set converterPages = new TreeSet();
+        Set validatorPages = new TreeSet();
+        Set tagsPages = new TreeSet();
+
+        int count = 0;
+        while (components.hasNext())
+        {
+            ComponentMeta component = (ComponentMeta) components.next();
+            if (canGenerate(component))
+            {                
+                String pageName = _generateComponentDoc(velocityEngine,baseContext,component);
+                if (pageName != null)
+                {
+                    componentPages.add(pageName);
+                    count++;
+                }
+            }
+        }
+        while (converters.hasNext())
+        {
+            ConverterMeta converter = (ConverterMeta) converters.next();
+            if (canGenerate(converter))
+            {
+                String pageName = _generateConverterDoc(velocityEngine,baseContext,converter);
+                if (pageName != null)
+                {
+                    converterPages.add(pageName);
+                    count++;
+                }
+            }
+        }
+        while (validators.hasNext())
+        {
+            ValidatorMeta validator = (ValidatorMeta) validators.next();
+            
+            if (canGenerate(validator))
+            {
+                String pageName = _generateValidatorDoc(velocityEngine,baseContext,validator);
+                if (pageName != null)
+                {
+                    validatorPages.add(pageName);
+                    count++;
+                }
+            }
+        }
+        while (tags.hasNext())
+        {
+            TagMeta tag = (TagMeta) tags.next();
+            
+            if (canGenerate(tag))
+            {
+                String pageName = _generateTagDoc(velocityEngine,baseContext,tag);
+                if (pageName != null)
+                {
+                    tagsPages.add(pageName);
+                    count++;
+                }                
+            }
+        }
+
+        Set otherPages = _gatherOtherTags();
+
+        getLog().info("Generated " + count + " page(s)");
+    }
+
+    private Set _gatherOtherTags()
+    {
+        TreeSet set = new TreeSet();
+        String subDir = _platformAgnosticPath(_platformAgnosticPath("xdoc/"
+                + _DOC_SUBDIRECTORY));
+        File siteSubDir = new File(siteDirectory, subDir);
+        if (siteSubDir.exists())
+        {
+            String[] files = siteSubDir.list();
+            for (int i = 0; i < files.length; i++)
+            {
+                String file = files[i];
+                if (file.endsWith(".xml"))
+                {
+                    set.add(file.substring(0, file.length() - 4));
+                }
+            }
+        }
+
+        return set;
+    }
+
+    public boolean usePageLinkBar()
+    {
+        return false;
+    }
+
+    private String _toPageName(String qName)
+    {
+        return MyfacesUtils.getTagPrefix(qName) + "_" + MyfacesUtils.getTagName(qName);
+    }
+
+    private String _generateComponentDoc(VelocityEngine velocityEngine, 
+            VelocityContext baseContext, ComponentMeta component)
+            throws Exception
+    {
+        if (component.getName() == null)
+        {
+            return null;
+        }
+        String pageName = _toPageName(component.getName());
+        
+        Context context = new VelocityContext(baseContext);
+        context.put("component", component);
+        
+        String baseContent = "";
+        
+        File xmlBaseFile = new File(baseFilesSourceDirectory, 
+                _platformAgnosticPath(pageName + "-base.xml"));
+        
+        if (xmlBaseFile != null && xmlBaseFile.exists())
+        {
+            if (getLog().isDebugEnabled())
+            {
+                getLog().debug("using base content file: "+xmlBaseFile.getPath());
+            }
+            
+            Reader reader = null;
+            try
+            {
+                reader = new FileReader(xmlBaseFile);
+                Xpp3Dom root = Xpp3DomBuilder.build(reader);
+                
+                StringWriter writer = new StringWriter();
+                
+                Xpp3Dom [] children = root.getChild("body").getChildren();
+                
+                for (int i = 0; i< children.length; i++)
+                {
+                    Xpp3Dom dom = children[i];
+                    Xpp3DomWriter.write(writer, dom);
+                }
+                baseContent = writer.toString();
+                writer.close();
+            }
+            catch (XmlPullParserException e)
+            {
+                throw new MojoExecutionException(
+                        "Error parsing base file: " + e.getMessage(), e);
+            }
+            finally
+            {
+                reader.close();
+            }
+        }
+        
+        baseContext.put("baseContent", baseContent);        
+        
+        Writer out = null;
+        
+        try
+        {        
+            File targetDir = new File(outputDirectory.getParentFile(),
+                    _platformAgnosticPath("generated-site/xdoc/"
+                            + _DOC_SUBDIRECTORY));
+            
+            if ( !targetDir.exists() )
+            {
+                targetDir.mkdirs();
+            }
+            File targetFile = new File(targetDir, pageName + ".xml");
+    
+            out = new OutputStreamWriter(new FileOutputStream(targetFile),
+                    "UTF-8");
+            
+            Template template = velocityEngine.getTemplate(getTemplateComponent());
+            
+            template.merge(context, out);
+            
+            out.flush();
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException(
+                    "Error merging velocity templates: " + e.getMessage(), e);
+        }
+        finally
+        {
+            IOUtil.close(out);
+            out = null;
+        }
+
+        return pageName;
+    }
+
+    private String _generateConverterDoc(VelocityEngine velocityEngine, 
+            VelocityContext baseContext, ConverterMeta converter)
+            throws Exception
+    {
+        if (converter.getName() == null)
+        {
+            return null;
+        }
+
+        String pageName = _toPageName(converter.getName());
+        
+        Context context = new VelocityContext(baseContext);
+        context.put("converter", converter);
+        
+        String baseContent = "";
+        
+        File xmlBaseFile = new File(baseFilesSourceDirectory, 
+                _platformAgnosticPath(pageName + "-base.xml"));
+        
+        if (xmlBaseFile != null && xmlBaseFile.exists())
+        {
+            if (getLog().isDebugEnabled())
+            {
+                getLog().debug("using base content file: "+xmlBaseFile.getPath());
+            }
+            
+            Reader reader = null;
+            try
+            {
+                reader = new FileReader(xmlBaseFile);
+                Xpp3Dom root = Xpp3DomBuilder.build(reader);
+                
+                StringWriter writer = new StringWriter();
+                
+                Xpp3Dom [] children = root.getChild("body").getChildren();
+                
+                for (int i = 0; i< children.length; i++)
+                {
+                    Xpp3Dom dom = children[i];
+                    Xpp3DomWriter.write(writer, dom);
+                }
+                baseContent = writer.toString();
+                writer.close();
+            }
+            catch (XmlPullParserException e)
+            {
+                throw new MojoExecutionException(
+                        "Error parsing base file: " + e.getMessage(), e);
+            }
+            finally
+            {
+                reader.close();
+            }
+        }
+        
+        baseContext.put("baseContent", baseContent);        
+        
+        Writer out = null;
+        
+        try
+        {        
+            File targetDir = new File(outputDirectory.getParentFile(),
+                    _platformAgnosticPath("generated-site/xdoc/"
+                            + _DOC_SUBDIRECTORY));
+            
+            if ( !targetDir.exists() )
+            {
+                targetDir.mkdirs();
+            }
+            File targetFile = new File(targetDir, pageName + ".xml");
+    
+            out = new OutputStreamWriter(new FileOutputStream(targetFile),
+                    "UTF-8");
+            
+            Template template = velocityEngine.getTemplate(getTemplateConverter());
+            
+            template.merge(context, out);
+            
+            out.flush();
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException(
+                    "Error merging velocity templates: " + e.getMessage(), e);
+        }
+        finally
+        {
+            IOUtil.close(out);
+            out = null;
+        }
+
+        return pageName;
+    }
+
+    private String _generateValidatorDoc(VelocityEngine velocityEngine, 
+            VelocityContext baseContext, ValidatorMeta validator)
+            throws Exception
+    {
+        if (validator.getName() == null)
+        {
+            return null;
+        }
+
+        String pageName = _toPageName(validator.getName());
+        
+        Context context = new VelocityContext(baseContext);
+        context.put("validator", validator);
+        
+        String baseContent = "";
+        
+        File xmlBaseFile = new File(baseFilesSourceDirectory, 
+                _platformAgnosticPath(pageName + "-base.xml"));
+        
+        if (xmlBaseFile != null && xmlBaseFile.exists())
+        {
+            if (getLog().isDebugEnabled())
+            {
+                getLog().debug("using base content file: "+xmlBaseFile.getPath());
+            }
+            
+            Reader reader = null;
+            try
+            {
+                reader = new FileReader(xmlBaseFile);
+                Xpp3Dom root = Xpp3DomBuilder.build(reader);
+                
+                StringWriter writer = new StringWriter();
+                
+                Xpp3Dom [] children = root.getChild("body").getChildren();
+                
+                for (int i = 0; i< children.length; i++)
+                {
+                    Xpp3Dom dom = children[i];
+                    Xpp3DomWriter.write(writer, dom);
+                }
+                baseContent = writer.toString();
+                writer.close();
+            }
+            catch (XmlPullParserException e)
+            {
+                throw new MojoExecutionException(
+                        "Error parsing base file: " + e.getMessage(), e);
+            }
+            finally
+            {
+                reader.close();
+            }
+        }
+        
+        baseContext.put("baseContent", baseContent);        
+        
+        Writer out = null;
+        
+        try
+        {        
+            File targetDir = new File(outputDirectory.getParentFile(),
+                    _platformAgnosticPath("generated-site/xdoc/"
+                            + _DOC_SUBDIRECTORY));
+            
+            if ( !targetDir.exists() )
+            {
+                targetDir.mkdirs();
+            }
+            File targetFile = new File(targetDir, pageName + ".xml");
+    
+            out = new OutputStreamWriter(new FileOutputStream(targetFile),
+                    "UTF-8");
+            
+            Template template = velocityEngine.getTemplate(getTemplateValidator());
+            
+            template.merge(context, out);
+            
+            out.flush();
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException(
+                    "Error merging velocity templates: " + e.getMessage(), e);
+        }
+        finally
+        {
+            IOUtil.close(out);
+            out = null;
+        }
+
+        return pageName;
+    }
+    
+    private String _generateTagDoc(VelocityEngine velocityEngine, 
+            VelocityContext baseContext, TagMeta tag)
+            throws Exception
+    {
+        if (tag.getName() == null)
+        {
+            return null;
+        }
+
+        String pageName = _toPageName(tag.getName());
+        
+        Context context = new VelocityContext(baseContext);
+        context.put("tag", tag);
+        
+        String baseContent = "";
+        
+        File xmlBaseFile = new File(baseFilesSourceDirectory, 
+                _platformAgnosticPath(pageName + "-base.xml"));
+        
+        if (xmlBaseFile != null && xmlBaseFile.exists())
+        {
+            if (getLog().isDebugEnabled())
+            {
+                getLog().debug("using base content file: "+xmlBaseFile.getPath());
+            }
+            
+            Reader reader = null;
+            try
+            {
+                reader = new FileReader(xmlBaseFile);
+                Xpp3Dom root = Xpp3DomBuilder.build(reader);
+                
+                StringWriter writer = new StringWriter();
+                
+                Xpp3Dom [] children = root.getChild("body").getChildren();
+                
+                for (int i = 0; i< children.length; i++)
+                {
+                    Xpp3Dom dom = children[i];
+                    Xpp3DomWriter.write(writer, dom);
+                }
+                baseContent = writer.toString();
+                writer.close();
+            }
+            catch (XmlPullParserException e)
+            {
+                throw new MojoExecutionException(
+                        "Error parsing base file: " + e.getMessage(), e);
+            }
+            finally
+            {
+                reader.close();
+            }
+        }
+        
+        baseContext.put("baseContent", baseContent);        
+        
+        Writer out = null;
+        
+        try
+        {        
+            File targetDir = new File(outputDirectory.getParentFile(),
+                    _platformAgnosticPath("generated-site/xdoc/"
+                            + _DOC_SUBDIRECTORY));
+            
+            if ( !targetDir.exists() )
+            {
+                targetDir.mkdirs();
+            }
+            File targetFile = new File(targetDir, pageName + ".xml");
+    
+            out = new OutputStreamWriter(new FileOutputStream(targetFile),
+                    "UTF-8");
+            
+            Template template = velocityEngine.getTemplate(getTemplateTag());
+            
+            template.merge(context, out);
+            
+            out.flush();
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException(
+                    "Error merging velocity templates: " + e.getMessage(), e);
+        }
+        finally
+        {
+            IOUtil.close(out);
+            out = null;
+        }
+
+        return pageName;
+    }
+    
+
+    static private final String _platformAgnosticPath(String path)
+    {
+        return path.replace('/', File.separatorChar);
+    }
+
+    protected MavenProject getProject()
+    {
+        return project;
+    }
+
+    protected String getOutputDirectory()
+    {
+        return outputDirectory.getAbsolutePath();
+    }
+
+    public String getName(Locale locale)
+    {
+        return "JSF Tag Documentation";
+    }
+
+    public String getDescription(Locale locale)
+    {
+        return "Documentation for JSF Tags";
+    }
+
+    public String getOutputName()
+    {
+        return "tagdoc";
+    }
+
+    protected Model getModel()
+    {
+        return _model;
+    }
+
+    protected List getMasterConfigs(MavenProject project)
+            throws MavenReportException
+    {
+        String resourcePath = "META-INF/maven-faces-plugin/faces-config.xml";
+        return getCompileDependencyResources(project, resourcePath);
+    }
+
+    protected List getCompileDependencyResources(MavenProject project,
+            String resourcePath) throws MavenReportException
+    {
+        try
+        {
+            ClassLoader cl = createCompileClassLoader(project);
+            Enumeration e = cl.getResources(resourcePath);
+            List urls = new ArrayList();
+            while (e.hasMoreElements())
+            {
+                URL url = (URL) e.nextElement();
+                urls.add(url);
+            }
+            return Collections.unmodifiableList(urls);
+        }
+        catch (IOException e)
+        {
+            throw new MavenReportException("Unable to get resources for path "
+                    + "\"" + resourcePath + "\"", e);
+        }
+
+    }
+
+    private ClassLoader createCompileClassLoader(MavenProject project)
+            throws MavenReportException
+    {
+        Thread current = Thread.currentThread();
+        ClassLoader cl = current.getContextClassLoader();
+
+        try
+        {
+            List classpathElements = project.getCompileClasspathElements();
+            if (!classpathElements.isEmpty())
+            {
+                String[] entries = (String[]) classpathElements
+                        .toArray(new String[0]);
+                URL[] urls = new URL[entries.length];
+                for (int i = 0; i < urls.length; i++)
+                {
+                    urls[i] = new File(entries[i]).toURL();
+                }
+                cl = new URLClassLoader(urls, cl);
+            }
+        }
+        catch (DependencyResolutionRequiredException e)
+        {
+            throw new MavenReportException("Error calculating scope classpath",
+                    e);
+        }
+        catch (MalformedURLException e)
+        {
+            throw new MavenReportException("Error calculating scope classpath",
+                    e);
+        }
+
+        return cl;
+    }
+
+    static public class URLCreationFactory extends
+            AbstractObjectCreationFactory
+    {
+        public Object createObject(Attributes attributes)
+                throws MalformedURLException
+        {
+            String href = attributes.getValue("href");
+            if (href == null)
+            {
+                throw new IllegalStateException("Missing href attribute");
+            }
+
+            URL master = (URL) digester.getRoot();
+            return new URL(master, href);
+        }
+    }
+
+    public String getTemplateComponent()
+    {
+        return templateComponent;
+    }
+
+    public String getTemplateConverter()
+    {
+        return templateConverter;
+    }
+
+    public String getTemplateValidator()
+    {
+        return templateValidator;
+    }
+
+    public String getTemplateTag()
+    {
+        return templateTag;
+    }
+    
+}
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java
new file mode 100644
index 0000000..e8f0d77
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocIndexReport.java
@@ -0,0 +1,478 @@
+/*
+ *  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.tagdoc;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Logger;
+
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.AbstractMavenReport;
+import org.apache.maven.reporting.MavenReportException;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.Flattener;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ClassMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.TagMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils;
+import org.apache.velocity.runtime.resource.ResourceManagerImpl;
+import org.codehaus.doxia.sink.Sink;
+import org.codehaus.doxia.site.renderer.SiteRenderer;
+
+/**
+ * Report for generating JSF tagdoc index based on myfaces-metadata.xml parsing.
+ * The content is generated using velocity in xdoc files (see TagdocContentMojo).
+ *
+ * @author Leonardo Uribe
+ * @goal tagdoc-index
+ */
+public class TagdocIndexReport extends AbstractMavenReport
+{
+    final Logger log = Logger.getLogger(TagdocIndexReport.class.getName());
+
+    private Model _model;
+
+    /**
+     * Specifies the directory where the report will be generated
+     *
+     * @parameter default-value="${project.reporting.outputDirectory}"
+     * @required
+     */
+    private File outputDirectory;
+
+    /**
+     * Directory where the original site is present.
+     * (TRIED using ${baseDir}/src/site;  that inserted a 'null' into
+     * the string for some reason.  TRIED using ${siteDirectory},
+     * which was undefined.  TRIED ${project.directory}src/site; which also
+     * inserted a null.  ${project.build.directory}/../src/site seems to work,
+     * though it assumes that ${project.build.directory} is 
+     * ${project.directory}/target.
+     * 
+     * @parameter default-value="${project.build.directory}/../src/site/"
+     * @required
+     */
+    private File siteDirectory;
+
+    /**
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @component
+     * @required
+     * @readonly
+     */
+    private SiteRenderer siteRenderer;
+
+    /**
+     * @parameter
+     */
+    private Map taglibs;
+
+    /**
+     * @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";
+
+    /**
+     * @parameter
+     */
+    private List modelIds;
+
+    /**
+     * component role="org.codehaus.plexus.velocity.VelocityComponent" roleHint="tagdoc"
+     */
+    //private VelocityComponent velocityComponent;
+    static private final String _DOC_SUBDIRECTORY = "tagdoc";
+
+    protected void executeReport(Locale locale) throws MavenReportException
+    {
+
+        if (modelIds == null)
+        {
+            modelIds = new ArrayList();
+            modelIds.add(project.getArtifactId());
+        }
+
+        if (taglibs == null)
+        {
+            taglibs = new HashMap();
+            taglibs.put("t", "http://myfaces.apache.org/tomahawk");
+        }
+
+        try
+        {
+            _model = IOUtils.loadModel(new File(buildDirectory, metadataFile));
+            new Flattener(_model).flatten();
+            _generateTagDocs();
+        }
+        catch (Exception e)
+        {
+            throw new MavenReportException("Couldn't generate tagdoc", e);
+        }
+    }
+
+    public boolean canGenerate(ClassMeta component)
+    {
+        if (modelIds.contains(component.getModelId()))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    public class CustomResourceManagerImpl extends ResourceManagerImpl
+    {
+
+        public CustomResourceManagerImpl()
+        {
+            super();
+        }
+
+    }
+
+    private void _generateTagDocs() throws Exception
+    {
+        Model model = getModel();
+        if (model.getComponents().size() == 0)
+        {
+            getLog().info("Nothing to generate - no components found");
+            return;
+        }
+
+        Iterator components = model.components();
+
+        Iterator validators = model.validators();
+
+        Iterator converters = model.converters();
+        
+        Iterator tags = model.tags();
+
+        // =-=AEW Note that only updating out-of-date components, etc. is
+        // permanently tricky, even if we had proper detection in place,
+        // because the index always has to have all docs
+        /*
+        if (!components.hasNext() && !converters.hasNext() && !validators.hasNext())
+        {
+          getLog().info("Nothing to generate - all docs are up to date");
+          return;
+        }
+        */
+
+        Set componentPages = new TreeSet();
+        Set converterPages = new TreeSet();
+        Set validatorPages = new TreeSet();
+        Set tagsPages = new TreeSet();
+
+        int count = 0;
+        while (components.hasNext())
+        {
+            ComponentMeta component = (ComponentMeta) components.next();
+            if (canGenerate(component))
+            {
+                String pageName = _generateComponentDoc(component);
+                if (pageName != null)
+                {
+                    componentPages.add(pageName);
+                    count++;
+                }
+            }
+        }
+        while (converters.hasNext())
+        {
+            ConverterMeta converter = (ConverterMeta) converters.next();
+            if (canGenerate(converter))
+            {
+                String pageName = _generateConverterDoc(converter);
+                if (pageName != null)
+                {
+                    converterPages.add(pageName);
+                    count++;
+                }
+            }
+        }
+        while (validators.hasNext())
+        {
+            ValidatorMeta validator = (ValidatorMeta) validators.next();
+
+            if (canGenerate(validator))
+            {
+                String pageName = _generateValidatorDoc(validator);
+                if (pageName != null)
+                {
+                    validatorPages.add(pageName);
+                    count++;
+                }
+            }
+        }
+        while (tags.hasNext())
+        {
+            TagMeta tag = (TagMeta) tags.next();
+            
+            if (canGenerate(tag))
+            {
+                String pageName = _generateTagDoc(tag);
+                if (pageName != null)
+                {
+                    tagsPages.add(pageName);
+                    count++;
+                }                
+            }
+        }
+
+        Set otherPages = _gatherOtherTags();
+
+        getLog().info("Generated " + count + " page(s)");
+
+        Sink sink = getSink();
+        sink.head();
+        sink.title();
+        sink.text("Tag library documentation");
+        sink.title_();
+        sink.head_();
+        sink.body();
+
+        sink.sectionTitle1();
+        sink.text("Tag library information");
+        sink.sectionTitle1_();
+        sink.section1();
+
+        for (Iterator i = taglibs.entrySet().iterator(); i.hasNext();)
+        {
+            Map.Entry entry = (Map.Entry) i.next();
+            sink.paragraph();
+
+            sink.bold();
+            sink.text("Short name:");
+            sink.bold_();
+            sink.nonBreakingSpace();
+            sink.text(entry.getKey().toString());
+            sink.lineBreak();
+
+            sink.bold();
+            sink.text("Namespace:");
+            sink.bold_();
+            sink.nonBreakingSpace();
+            sink.text(entry.getValue().toString());
+            sink.lineBreak();
+
+            sink.paragraph_();
+        }
+
+        sink.section1_();
+
+        _writeIndexSection(sink, componentPages, "Components");
+        _writeIndexSection(sink, converterPages, "Converters");
+        _writeIndexSection(sink, validatorPages, "Validators");
+        _writeIndexSection(sink, tagsPages, "JSF Tags");
+        _writeIndexSection(sink, otherPages, "Miscellaneous");
+
+        sink.body_();
+    }
+
+    private Set _gatherOtherTags()
+    {
+        TreeSet set = new TreeSet();
+        String subDir = _platformAgnosticPath(_platformAgnosticPath("xdoc/"
+                + _DOC_SUBDIRECTORY));
+        File siteSubDir = new File(siteDirectory, subDir);
+        if (siteSubDir.exists())
+        {
+            String[] files = siteSubDir.list();
+            for (int i = 0; i < files.length; i++)
+            {
+                String file = files[i];
+                if (file.endsWith(".xml"))
+                {
+                    set.add(file.substring(0, file.length() - 4));
+                }
+            }
+        }
+
+        return set;
+    }
+
+    private void _writeIndexSection(Sink sink, Set pages, String title)
+    {
+        if (pages.isEmpty())
+        {
+            return;
+        }
+
+        sink.sectionTitle1();
+        sink.text(title);
+        sink.sectionTitle1_();
+        sink.section1();
+        sink.table();
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text("Tag Name");
+        sink.tableHeaderCell_();
+        sink.tableRow_();
+
+        Iterator iter = pages.iterator();
+        while (iter.hasNext())
+        {
+            sink.tableRow();
+            sink.tableCell();
+
+            String name = (String) iter.next();
+            String tagName = "<" + name.replace('_', ':') + ">";
+
+            sink.link(_DOC_SUBDIRECTORY + "/" + name + ".html");
+            sink.text(tagName);
+            sink.link_();
+
+            sink.tableCell_();
+            sink.tableRow_();
+        }
+
+        sink.table_();
+        sink.section1_();
+    }
+
+    public boolean usePageLinkBar()
+    {
+        return false;
+    }
+
+    private String _toPageName(String qName)
+    {
+        return MyfacesUtils.getTagPrefix(qName) + "_"
+                + MyfacesUtils.getTagName(qName);
+    }
+
+    private String _generateComponentDoc(ComponentMeta component)
+            throws Exception
+    {
+        if (component.getName() == null)
+        {
+            return null;
+        }
+        String pageName = _toPageName(component.getName());
+
+        return pageName;
+    }
+
+    private String _generateConverterDoc(ConverterMeta converter)
+            throws IOException
+    {
+        if (converter.getName() == null)
+        {
+            return null;
+        }
+
+        String pageName = _toPageName(converter.getName());
+
+        return pageName;
+    }
+
+    private String _generateValidatorDoc(ValidatorMeta validator)
+            throws IOException
+    {
+        if (validator.getName() == null)
+        {
+            return null;
+        }
+
+        String pageName = _toPageName(validator.getName());
+
+        return pageName;
+    }
+    
+    private String _generateTagDoc(TagMeta tag)
+        throws IOException
+    {
+        if (tag.getName() == null)
+        {
+            return null;
+        }
+        
+        String pageName = _toPageName(tag.getName());
+        
+        return pageName;
+    }    
+
+    static private final String _platformAgnosticPath(String path)
+    {
+        return path.replace('/', File.separatorChar);
+    }
+
+    protected MavenProject getProject()
+    {
+        return project;
+    }
+
+    protected String getOutputDirectory()
+    {
+        return outputDirectory.getAbsolutePath();
+    }
+
+    protected SiteRenderer getSiteRenderer()
+    {
+        return siteRenderer;
+    }
+
+    public String getName(Locale locale)
+    {
+        return "JSF Tag Documentation";
+    }
+
+    public String getDescription(Locale locale)
+    {
+        return "Documentation for JSF Tags";
+    }
+
+    public String getOutputName()
+    {
+        return "tagdoc";
+    }
+
+    protected Model getModel()
+    {
+        return _model;
+    }
+
+}
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java
new file mode 100644
index 0000000..84b4bf3
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/tagdoc/TagdocUtils.java
@@ -0,0 +1,162 @@
+/*
+ *  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.tagdoc;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.AttributeHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.AttributeMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RenderKitMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RendererMeta;
+
+public class TagdocUtils
+{
+    
+    static public final String platformAgnosticPath(String path)
+    {
+        return path.replace('/', File.separatorChar);
+    }
+    
+    static public String getDisplayType(String className, String name,
+            String type)
+    {
+        if (type.startsWith("java.lang."))
+        {
+            return type.substring("java.lang.".length());
+        }
+        else if ("binding".equals(name))
+        {
+            StringTokenizer tokens = new StringTokenizer(className, ".", true);
+            String out = "";
+            while (tokens.hasMoreTokens())
+            {
+                String token = tokens.nextToken();
+                out = out + token;
+                // Give ourselves an opportunity for a line break after "component.";
+                if (out.endsWith("component."))
+                {
+                    out = out + "<wbr/>";
+                }
+            }
+
+            return out;
+        }
+
+        return type;
+    }
+    
+    static public List getSortedPropertyList(PropertyHolder component)
+    {
+        // Sort the names
+        TreeSet attributes = new TreeSet();
+        Iterator attrs = component.properties();
+        while (attrs.hasNext())
+        {
+            PropertyMeta property = (PropertyMeta) attrs.next();
+            if (!property.isTagExcluded().booleanValue())
+            {
+                attributes.add(property.getName());
+            }
+        }
+
+        // Now get a list of PropertyMetas
+        List list = new ArrayList();
+        Iterator iter = attributes.iterator();
+        while (iter.hasNext())
+        {
+            String attrName = (String) iter.next();
+            list.add(component.getProperty(attrName));
+        }
+        return list;        
+    }
+    
+    static public List getSortedFacetList(FacetHolder component)
+    {
+        TreeSet facetNames = new TreeSet();
+        Iterator iter = component.facets();
+        while (iter.hasNext())
+        {
+            facetNames.add(((FacetMeta) iter.next()).getName());
+        }
+        
+        // Now get a list of PropertyMetas
+        List list = new ArrayList();
+        Iterator nameIter = facetNames.iterator();
+        while (nameIter.hasNext())
+        {
+            String name = (String) nameIter.next();
+            list.add(component.getFacet(name));
+        }
+        return list;
+    }
+    
+    static public List getSortedAttributeList(AttributeHolder component)
+    {
+        // Sort the names
+        TreeSet attributes = new TreeSet();
+        Iterator attrs = component.attributes();
+        while (attrs.hasNext())
+        {
+            AttributeMeta attribute = (AttributeMeta) attrs.next();
+            attributes.add(attribute.getName());
+        }
+
+        // Now get a list of PropertyMetas
+        List list = new ArrayList();
+        Iterator iter = attributes.iterator();
+        while (iter.hasNext())
+        {
+            String attrName = (String) iter.next();
+            list.add(component.getAttribute(attrName));
+        }
+        return list;        
+    }
+        
+    static public Map getRendererClasses(ComponentMeta component, Model model)
+    {
+        Map componentRenderers = new HashMap(); 
+        List renderKits = model.getRenderKits();
+        if (renderKits != null)
+        {
+            for (Iterator it = renderKits.iterator();it.hasNext();)
+            {
+                RenderKitMeta renderkit = (RenderKitMeta) it.next();
+                RendererMeta renderer = renderkit.findRenderer(component.getFamily(), component.getRendererType());
+                if (renderer != null)
+                {
+                    componentRenderers.put(renderkit.getRenderKitId(), renderer.getClassName());
+                }
+            }
+        }
+        return componentRenderers;
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/componentClass11.vm b/myfaces-builder-plugin/src/main/resources/META-INF/componentClass11.vm
new file mode 100644
index 0000000..dde95ba
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/componentClass11.vm
@@ -0,0 +1,265 @@
+## Velocity template used to generate JSF1.1-compatible component classes
+## from component meta-data.
+##
+## Note that there are two types of component generation:
+##  * "subclass mode" (use annotated class as a parent class)
+##  * "template mode" (use annotated class as a template)
+## This template file is used for both.
+##
+## Variable $component refers to a ComponentMeta object to process
+## Variable $utils refers to an instance of MyfacesUtils.
+##
+## When "template mode" is being used then variable $innersource
+## holds a String containing all the non-abstract functions defined
+## in the annotated class.
+##
+## The java package of the generated class is always the same as
+## the package in which the annotated class exists.
+##
+## This file is not actually used (except for unit testing). Each
+## project that uses the myfaces-builder-plugin is expected to copy
+## this file into its own META-INF dir, from where the builder
+## plugin will retrieve it.
+##
+/*
+ *  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 ${component.packageName};
+
+import javax.faces.component.UIComponent;
+import javax.faces.el.ValueBinding;
+import javax.faces.context.FacesContext;
+import $component.parentClassName;
+$utils.importTagClasses($component)
+
+#if ($component.isTemplate())
+#set ($generatedClassParent = $component.sourceClassParentClassName)
+#else
+#set ($generatedClassParent = $component.sourceClassName)
+#end
+// Generated from class ${component.sourceClassName}.
+//
+// WARNING: This file was automatically generated. Do not edit it directly,
+//          or you will lose your changes.
+public class ${utils.getClassFromFullClass($component.className)} extends $generatedClassParent
+#if ($component.implements)
+    implements $component.implements
+#end
+{
+#if ($component.serialuid)
+    private static final long serialVersionUID = ${component.serialuid}; 
+#end  
+
+##    static public final String COMPONENT_FAMILY =
+##        "$component.family";
+    static public final String COMPONENT_TYPE =
+        "$component.type";
+
+#if ($innersource)
+    //BEGIN CODE COPIED FROM $component.sourceClassName 
+$innersource
+    //END CODE COPIED FROM $component.sourceClassName
+#end
+
+    public ${utils.getClassFromFullClass($component.className)}()
+    {
+#if ($component.rendererType)
+#if ($component.rendererType == "")
+        setRendererType(null);
+#else
+        setRendererType("$component.rendererType");
+#end
+#else
+        setRendererType(null);
+#end
+    }
+
+## On myfaces 1.1 the family is inherited, so this could be commented    
+##    public String getFamily()
+##    {
+##        return COMPONENT_FAMILY;
+##    }
+    
+#set ($propertyList = ${component.propertyComponentList})
+
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $utils.getClassFromFullClass($property.className))
+#if($utils.getDefaultValueField($property)) 
+#set ($defaultValue = $utils.getDefaultValueField($property))
+#else
+#set ($defaultValue = false)
+#end
+    // Property: $property.name
+#if ($property.isLiteralOnly() || $property.isTagExcluded() )
+    private $type $field #if($defaultValue) = $defaultValue;#{else};#{end}
+
+     
+#else
+    private $type $field;
+    
+#end
+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded()
+    && !$property.isLiteralOnly() )
+    private boolean ${field}Set;
+    
+#if ($property.isSetMethod())
+    $property.setMethodScope boolean $utils.getPrefixedPropertyName("isSet", $property.name)()
+    {
+        return ${field}Set;
+    }
+#end
+#end
+#if($property.isLocalMethod())
+#if("boolean" == $type)
+#set ($methodName = $utils.getPrefixedPropertyName("isLocal", $property.name))
+#else
+#set ($methodName = $utils.getPrefixedPropertyName("getLocal", $property.name))
+#end
+    final $property.localMethodScope $type ${methodName}()
+    {
+        return $field;
+    }
+     
+#end
+    public $type $utils.getMethodReaderFromProperty($property.name, $type)()
+    {
+#if ($property.isTagExcluded() || $property.isLiteralOnly())
+        return $field;
+#else
+#if ($utils.isPrimitiveClass($type))
+        if (${field}Set)
+#else
+        if ($field != null)
+#end
+        {
+            return $field;
+        }
+        ValueBinding vb = getValueBinding("$property.name");
+        if (vb != null)
+        {
+#if ($utils.isPrimitiveClass($type))
+            return ($utils.castIfNecessary($type) vb.getValue(getFacesContext())).${type}Value();
+#else
+#set ($pritype = $utils.getPrimitiveType($property.className))
+#if ($utils.isPrimitiveClass($pritype))
+            Object value = vb == null ? null : vb.getValue(getFacesContext());
+            if (!(value instanceof $type)){
+                value = ${type}.valueOf(value.toString());
+            }            
+            return $utils.castIfNecessary($type) value;
+#elseif ($type == "String")
+## MYFACES-2006 use toString(), so Numeric ValueBinding could be converted as
+## Strings and do not cause ClassCastException 
+## (only applies for JSF 1.1 due to backward compatibility) 
+            return $utils.castIfNecessary($type) vb.getValue(getFacesContext()).toString();
+#else
+            return $utils.castIfNecessary($type) vb.getValue(getFacesContext());
+#end
+#end
+        }
+#if ($defaultValue)
+        return $defaultValue; 
+#elseif ($utils.isPrimitiveClass($type))
+        return $utils.primitiveDefaultValue($type);
+#else       
+        return null;
+#end
+#end
+    }
+
+    public void $utils.getPrefixedPropertyName("set", $property.name)($type $utils.getVariableFromName($property.name))
+    {
+        this.$field = $utils.getVariableFromName($property.name);
+#if ($utils.isPrimitiveClass($type) && !$property.isTagExcluded() 
+     && !$property.isLiteralOnly())
+        this.${field}Set = true;        
+#end
+    }
+#end
+
+    public Object saveState(FacesContext facesContext)
+    {
+#set ($primitiveCount = $propertyList.size() + 1)
+#foreach( $property in $propertyList )
+#if($utils.isPrimitiveClass($property.className) && 
+    !$property.isLiteralOnly())
+#set ($primitiveCount = $primitiveCount + 1)
+#end
+#end
+        Object[] values = new Object[$primitiveCount];
+        values[0] = super.saveState(facesContext);
+#set ($arrayIndex = 0)
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $property.className)
+#set ($arrayIndex = $arrayIndex + 1)
+#if ($property.jspName == "validator" && $property.isMethodBinding() )
+        values[$arrayIndex] = saveAttachedState(facesContext,${field}List);
+#elseif ( $property.isStateHolder() )## || $utils.isConverter($type)
+        values[$arrayIndex] = saveAttachedState(facesContext,$field);
+#elseif($utils.isPrimitiveClass($type))
+#if ($type == "boolean")
+        values[$arrayIndex] = ${utils.getBoxedClass($type)}.valueOf($field);
+#else
+        values[$arrayIndex] = new ${utils.getBoxedClass($type)}($field);
+#end
+#else
+        values[$arrayIndex] = $field;
+#end
+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded()
+    && !$property.isLiteralOnly() )
+#set ($arrayIndex = $arrayIndex + 1)
+        values[$arrayIndex] = Boolean.valueOf(${field}Set);
+#end
+#end
+        return values; 
+    }
+
+    public void restoreState(FacesContext facesContext, Object state)
+    {
+        Object[] values = (Object[])state;
+        super.restoreState(facesContext,values[0]);
+#set ($arrayIndex = 0)
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $property.className)
+#set ($arrayIndex = $arrayIndex + 1)
+#if ( $property.isStateHolder() )
+#if ($property.jspName == "validator" && $property.isMethodBinding() )
+        ${field}List = (List<Validator>) restoreAttachedState(facesContext,values[$arrayIndex]);
+#elseif ($utils.isList($type))
+        $field = (List) restoreAttachedState(facesContext,values[$arrayIndex]);
+#else
+        $field = $utils.castIfNecessary($type) restoreAttachedState(facesContext,values[$arrayIndex]); 
+#end
+#elseif ($utils.isConverter($type)) 
+        $field = (Converter) restoreAttachedState(facesContext,values[$arrayIndex]);
+#elseif ($utils.isPrimitiveClass($type))
+        $field = ($utils.castIfNecessary($type) values[$arrayIndex]).${type}Value();
+#else
+        $field = $utils.castIfNecessary($type) values[$arrayIndex];
+#end
+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded()
+    && !$property.isLiteralOnly() )
+#set ($arrayIndex = $arrayIndex + 1)
+        ${field}Set = ((Boolean) values[$arrayIndex]).booleanValue();
+#end
+#end
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/componentClass12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/componentClass12.vm
new file mode 100644
index 0000000..2580c9e
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/componentClass12.vm
@@ -0,0 +1,256 @@
+## Velocity template used to generate JSF1.2-compatible component classes

+## from component meta-data.

+##

+## Note that there are two types of component generation:

+##  * "subclass mode" (use annotated class as a parent class)

+##  * "template mode" (use annotated class as a template)

+## This template file is used for both.

+##

+## Variable $component refers to a ComponentMeta object to process

+## Variable $utils refers to an instance of MyfacesUtils.

+##

+## When "template mode" is being used then variable $innersource

+## holds a String containing all the non-abstract functions defined

+## in the annotated class.

+##

+## The java package of the generated class is always the same as

+## the package in which the annotated class exists.

+##

+/*

+ *  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 ${component.packageName};

+

+import javax.el.ValueExpression;

+import javax.faces.context.FacesContext;

+$utils.importTagClasses($component)

+

+#if ($component.isTemplate())

+#set ($generatedClassParent = $component.sourceClassParentClassName)

+#else

+#set ($generatedClassParent = $component.sourceClassName)

+#end

+// Generated from class ${component.sourceClassName}.

+//

+// WARNING: This file was automatically generated. Do not edit it directly,

+//          or you will lose your changes.

+public class ${utils.getClassFromFullClass($component.className)} extends $generatedClassParent

+#if ($component.implements)

+    implements $component.implements

+#end

+{

+#if ($component.serialuid)

+    private static final long serialVersionUID = ${component.serialuid}; 

+#end  

+

+    static public final String COMPONENT_FAMILY =

+        "$component.family";

+    static public final String COMPONENT_TYPE =

+        "$component.type";

+#if ($component.rendererType)

+#if (!($component.rendererType == ""))

+    static public final String DEFAULT_RENDERER_TYPE = 

+        "$component.rendererType";

+#end

+#end

+

+#if ($innersource)

+    //BEGIN CODE COPIED FROM $component.sourceClassName 

+$innersource

+    //END CODE COPIED FROM $component.sourceClassName

+#end

+

+    public ${utils.getClassFromFullClass($component.className)}()

+    {

+#if ($component.rendererType)

+#if ($component.rendererType == "")

+        setRendererType(null);

+#else

+        setRendererType("$component.rendererType");

+#end

+#else

+        setRendererType(null);

+#end

+    }

+

+## On myfaces 1.1 the family is inherited, so this could be commented

+## On other this should not be commented    

+    public String getFamily()

+    {

+        return COMPONENT_FAMILY;

+    }

+    

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

+

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#set ($type = $utils.getClassFromFullClass($property.className))

+#if($utils.getDefaultValueField($property)) 

+#set ($defaultValue = $utils.getDefaultValueField($property))

+#else

+#set ($defaultValue = false)

+#end

+    // Property: $property.name

+#if ($property.isLiteralOnly() || $property.isTagExcluded() )

+    private $type $field #if($defaultValue) = $defaultValue;#{else};#{end}

+

+     

+#else

+    private $type $field;

+    

+#end

+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded()

+    && !$property.isLiteralOnly() )

+    private boolean ${field}Set;

+    

+#if ($property.isSetMethod())

+    $property.setMethodScope boolean $utils.getPrefixedPropertyName("isSet", $property.name)()

+    {

+        return ${field}Set;

+    }

+#end

+#end

+#if($property.isLocalMethod())

+#if("boolean" == $type)

+#set ($methodName = $utils.getPrefixedPropertyName("isLocal", $property.name))

+#else

+#set ($methodName = $utils.getPrefixedPropertyName("getLocal", $property.name))

+#end

+    final $property.localMethodScope $type ${methodName}()

+    {

+        return $field;

+    }

+     

+#end

+    public $type $utils.getMethodReaderFromProperty($property.name, $type)()

+    {

+#if ($property.isTagExcluded() || $property.isLiteralOnly())

+        return $field;

+#else

+#if ($utils.isPrimitiveClass($type))

+        if (${field}Set)

+#else

+        if ($field != null)

+#end

+        {

+            return $field;

+        }

+        ValueExpression vb = getValueExpression("$property.name");

+        if (vb != null)

+        {

+#if ($utils.isPrimitiveClass($type))

+            return ($utils.castIfNecessary($type) vb.getValue(getFacesContext().getELContext())).${type}Value();

+#else

+#set ($pritype = $utils.getPrimitiveType($property.className))

+#if ($utils.isPrimitiveClass($pritype))

+            Object value = vb == null ? null : vb.getValue(getFacesContext().getELContext());

+            if (!(value instanceof $type)){

+                value = ${type}.valueOf(value.toString());

+            }            

+            return $utils.castIfNecessary($type) value;

+#else

+            return $utils.castIfNecessary($type) vb.getValue(getFacesContext().getELContext());

+#end

+#end

+        }

+#if ($defaultValue)

+        return $defaultValue; 

+#elseif ($utils.isPrimitiveClass($type))

+        return $utils.primitiveDefaultValue($type);

+#else       

+        return null;

+#end

+#end

+    }

+

+    public void $utils.getPrefixedPropertyName("set", $property.name)($type $utils.getVariableFromName($property.name))

+    {

+        this.$field = $utils.getVariableFromName($property.name);

+#if ($utils.isPrimitiveClass($type) && !$property.isTagExcluded() 

+     && !$property.isLiteralOnly())

+        this.${field}Set = true;        

+#end

+    }

+#end

+

+    public Object saveState(FacesContext facesContext)

+    {

+#set ($primitiveCount = $propertyList.size() + 1)

+#foreach( $property in $propertyList )

+#if($utils.isPrimitiveClass($property.className) && 

+    !$property.isLiteralOnly())

+#set ($primitiveCount = $primitiveCount + 1)

+#end

+#end

+        Object[] values = new Object[$primitiveCount];

+        values[0] = super.saveState(facesContext);

+#set ($arrayIndex = 0)

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#set ($type = $property.className)

+#set ($arrayIndex = $arrayIndex + 1)

+#if ($property.jspName == "validator" && $property.isMethodBinding() )

+        values[$arrayIndex] = saveAttachedState(facesContext,${field}List);

+#elseif ( $property.isStateHolder() )## || $utils.isConverter($type)

+        values[$arrayIndex] = saveAttachedState(facesContext,$field);

+#elseif($utils.isPrimitiveClass($type))

+        values[$arrayIndex] = ${utils.getBoxedClass($type)}.valueOf($field);

+#else

+        values[$arrayIndex] = $field;

+#end

+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded()

+    && !$property.isLiteralOnly() )

+#set ($arrayIndex = $arrayIndex + 1)

+        values[$arrayIndex] = Boolean.valueOf(${field}Set);

+#end

+#end

+        return values; 

+    }

+

+    public void restoreState(FacesContext facesContext, Object state)

+    {

+        Object[] values = (Object[])state;

+        super.restoreState(facesContext,values[0]);

+#set ($arrayIndex = 0)

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#set ($type = $property.className)

+#set ($arrayIndex = $arrayIndex + 1)

+#if ( $property.isStateHolder() )

+#if ($property.jspName == "validator" && $property.isMethodBinding() )

+        ${field}List = (List<Validator>) restoreAttachedState(facesContext,values[$arrayIndex]);

+#elseif ($utils.isList($type))

+        $field = (List) restoreAttachedState(facesContext,values[$arrayIndex]);

+#else

+        $field = $utils.castIfNecessary($type) restoreAttachedState(facesContext,values[$arrayIndex]); 

+#end

+#elseif ($utils.isConverter($type)) 

+        $field = (Converter) restoreAttachedState(facesContext,values[$arrayIndex]);

+#elseif ($utils.isPrimitiveClass($type))

+        $field = ($utils.castIfNecessary($type) values[$arrayIndex]).${type}Value();

+#else

+        $field = $utils.castIfNecessary($type) values[$arrayIndex];

+#end

+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded()

+    && !$property.isLiteralOnly() )

+#set ($arrayIndex = $arrayIndex + 1)

+        ${field}Set = ((Boolean) values[$arrayIndex]).booleanValue();

+#end

+#end

+    }

+}

diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/componentClassMacros11.vm b/myfaces-builder-plugin/src/main/resources/META-INF/componentClassMacros11.vm
new file mode 100644
index 0000000..25af52b
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/componentClassMacros11.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/myfaces-builder-plugin/src/main/resources/META-INF/facelets-taglib.vm b/myfaces-builder-plugin/src/main/resources/META-INF/facelets-taglib.vm
new file mode 100644
index 0000000..fd157c9
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/facelets-taglib.vm
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+ * 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 facelet-taglib

+  PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">

+<facelet-taglib xmlns="http://java.sun.com/JSF/Facelet">

+

+    <namespace>$uri</namespace>

+

+    <!-- Component Tags -->

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

+#foreach( $component in $componentList )

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

+    && ($component.name))

+#if (!$component.isConfigExcluded())

+    <tag>

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

+        <component>

+            <component-type>$component.type</component-type>

+#if ($component.rendererType)

+#if (!($component.rendererType == ""))

+            <renderer-type>$component.rendererType</renderer-type>

+#end

+#end

+#if ($component.tagHandler)

+            <handler-class>$component.tagHandler</handler-class>

+#end

+        </component>

+    </tag>

+#end

+#end

+#end

+

+   <!-- Converter tags -->

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

+#foreach( $component in $componentList )

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

+    && ($component.name))

+#if ($component.converterId) 

+    <tag>

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

+        <converter>

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

+        </converter>

+    </tag>

+#end

+#end

+#end

+

+   <!-- Validator tags -->

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

+#foreach( $component in $componentList )

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

+    && ($component.name))

+#if ($component.validatorId)

+    <tag>

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

+        <validator>

+            <validator-id>$component.validatorId</validator-id>

+        </validator>      

+    </tag>

+#end

+#end

+#end

+    

+   <!-- Single Tags -->

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

+#foreach( $tag in $tagList )

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

+#if ($tag.tagHandler)

+   <tag>

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

+      <handler-class>$tag.tagHandler</handler-class>

+   </tag>

+#end

+#end

+#end

+

+</facelet-taglib>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/faces-config11.vm b/myfaces-builder-plugin/src/main/resources/META-INF/faces-config11.vm
new file mode 100644
index 0000000..f688b2e
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/faces-config11.vm
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+
+<!DOCTYPE faces-config PUBLIC
+ "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
+ "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
+
+<!--
+ * 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.
+-->
+
+<faces-config xmlns="http://java.sun.com/JSF/Configuration">
+
+$baseContent
+
+#set ($componentList = ${model.getComponents()})
+#foreach( $component in $componentList )
+#if ($modelIds.contains($component.modelId) 
+    && !($component.className.contains("UIComponent"))
+    && !($component.isConfigExcluded()))
+  <component>
+    <component-type>$component.type</component-type>
+    <component-class>$component.className</component-class>
+  </component>    
+#end
+#end
+#set ($converterList = ${model.getConverters()})
+#foreach( $converter in $converterList )
+#if ($modelIds.contains($converter.modelId))
+  <converter>
+    <converter-id>$converter.converterId</converter-id>
+    <converter-class>$converter.className</converter-class>
+  </converter>
+#end
+#end
+#set ($validatorList = ${model.getValidators()})
+#foreach( $validator in $validatorList )
+#if ($modelIds.contains($validator.modelId) &&
+    !($validator.isConfigExcluded().booleanValue()) &&
+    $validator.validatorId)
+  <validator>
+    <validator-id>$validator.validatorId</validator-id>
+    <validator-class>$validator.className</validator-class>
+  </validator>
+#end
+#end
+#set ($renderKitList = ${model.getRenderKits()})
+#foreach( $renderKit in $renderKitList )
+  <render-kit>
+    <render-kit-id>$renderKit.renderKitId</render-kit-id>
+#if ($renderKit.className)
+    <render-kit-class>$renderKit.className</render-kit-class>
+#end
+#set ($rendererList = ${renderKit.getRenderers()})
+#foreach( $renderer in $rendererList )
+      <renderer>
+        <component-family>$renderer.componentFamily</component-family>
+        <renderer-type>$renderer.rendererType</renderer-type>
+        <renderer-class>$renderer.className</renderer-class>
+      </renderer>
+#end
+  </render-kit>
+#end
+</faces-config>
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/faces-config12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/faces-config12.vm
new file mode 100644
index 0000000..21630ca
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/faces-config12.vm
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>

+

+<!--

+ * 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.

+-->

+

+<faces-config xmlns="http://java.sun.com/xml/ns/javaee" 

+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" 

+              version="1.2">

+

+$baseContent

+

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

+#foreach( $component in $componentList )

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

+    && !($component.className.contains("UIComponent"))

+    && !($component.isConfigExcluded()))

+  <component>

+    <component-type>$component.type</component-type>

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

+  </component>    

+#end

+#end

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

+#foreach( $converter in $converterList )

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

+  <converter>

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

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

+  </converter>

+#end

+#end

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

+#foreach( $validator in $validatorList )

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

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

+    $validator.validatorId)

+  <validator>

+    <validator-id>$validator.validatorId</validator-id>

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

+  </validator>

+#end

+#end

+#set ($renderKitList = ${model.getRenderKits()})

+#foreach( $renderKit in $renderKitList )

+  <render-kit>

+    <render-kit-id>$renderKit.renderKitId</render-kit-id>

+#if ($renderKit.className)

+    <render-kit-class>$renderKit.className</render-kit-class>

+#end

+#set ($rendererList = ${renderKit.getRenderers()})

+#foreach( $renderer in $rendererList )

+      <renderer>

+        <component-family>$renderer.componentFamily</component-family>

+        <renderer-type>$renderer.rendererType</renderer-type>

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

+      </renderer>

+#end

+  </render-kit>

+#end

+</faces-config>

diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/myfaces_html.vm b/myfaces-builder-plugin/src/main/resources/META-INF/myfaces_html.vm
new file mode 100644
index 0000000..b467dce
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/myfaces_html.vm
@@ -0,0 +1,52 @@
+<?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 xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
+
+$baseContent
+
+#set ($componentList = ${model.getComponents()})
+#foreach( $component in $componentList )
+#if ($modelIds.contains($component.modelId) 
+    && ($component.name))
+#if ($utils.getTagPrefix($component.name) == "h") 
+   <tag>
+      <name>$utils.getTagName($component.name)</name>
+      <tag-class>$component.tagClass</tag-class>
+      <body-content>JSP</body-content>
+      <description></description>
+      
+#set ($propertyList = ${component.propertyList})
+#foreach( $property in $propertyList )
+#if (!$property.tagExcluded)
+      <attribute>
+         <name>$property.name</name>
+         <required>$property.isRequired()</required>
+         <rtexprvalue>false</rtexprvalue>
+         <type>java.lang.String</type>
+         <description></description>
+      </attribute>
+#end
+#end
+   </tag>
+#end
+#end
+#end
+</taglib>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/tagClass11.vm b/myfaces-builder-plugin/src/main/resources/META-INF/tagClass11.vm
new file mode 100644
index 0000000..3768639
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/tagClass11.vm
@@ -0,0 +1,170 @@
+// WARNING: This file was automatically generated. Do not edit it directly,
+//          or you will lose your changes.
+/*
+ *  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 ${component.tagPackage};
+
+import javax.faces.component.UIComponent;
+import javax.faces.el.ValueBinding;
+import javax.faces.context.FacesContext;
+import ${component.tagSuperclass};
+$utils.importTagClasses($component)
+
+// Generated from class ${component.sourceClassName}.
+//
+// WARNING: This file was automatically generated. Do not edit it directly,
+//          or you will lose your changes.
+public class $utils.getClassFromFullClass($component.tagClass) extends ${utils.getClassFromFullClass($component.tagSuperclass)}{
+
+    public $utils.getClassFromFullClass($component.tagClass)()
+    {    
+    }
+    
+    public String getComponentType()
+    {
+#if ($component.type)
+        return "$component.type";
+#else
+        return null;
+#end
+    }
+
+    public String getRendererType()
+    {
+#if ($component.rendererType && !($component.rendererType == ""))
+        return "$component.rendererType";
+#else
+        return null;
+#end
+    }
+
+#set ($propertyList = ${component.propertyTagList})
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $utils.getJspPropertyType11($property))
+ 
+    private $type $field;
+    
+#set ($var = $utils.getVariableFromName($property.name))
+    public void $utils.getPrefixedPropertyName("set", $property.jspName)($type $var)
+    {
+        $field = $var;
+    }
+#end
+
+    protected void setProperties(UIComponent component)
+    {
+        if (!(component instanceof $component.className))
+        {
+            throw new IllegalArgumentException("Component "+
+                component.getClass().getName() +" is no $component.className");
+        }
+        
+        $component.className comp = ($component.className) component;
+        
+        super.setProperties(component);
+        
+        FacesContext context = getFacesContext();
+
+#foreach( $property in $propertyList )##            1
+#set ($field = $property.fieldName)
+#set ($type = $utils.getJspPropertyType11($property))
+#if ($utils.isConverter($property.className))##                   2
+        if ($field != null)
+        {
+            if (isValueReference($field))
+            {
+                ValueBinding vb = context.getApplication().createValueBinding($field);
+                comp.setValueBinding("$property.name", vb);
+            }
+            else
+            {
+                Converter converter = getFacesContext().getApplication().createConverter($field);
+                comp.setConverter(converter);
+            }
+        }
+#elseif ($property.isMethodBinding())##                 2
+        if ($field != null)
+        {
+#if ($utils.isStringMethodBindingReturnType($property.methodBindingSignature))##3
+            MethodBinding mb;
+            if (isValueReference($field))
+            {
+                mb = context.getApplication().createMethodBinding(
+                    $field, $utils.getSignatureParams($property.methodBindingSignature));            
+            }
+            else
+            {
+#if ($property.jspName == "action")##                      4
+                mb = new org.apache.myfaces.shared_impl.el.SimpleActionMethodBinding($field);
+#else##                                                   4
+                throw new IllegalStateException("Invalid expression " + $field);
+#end##                                                    4
+            }
+#else##                                                 3
+            MethodBinding mb = context.getApplication().createMethodBinding(
+                $field, $utils.getSignatureParams($property.methodBindingSignature));
+#end##                                                  3
+            comp.${utils.getPrefixedPropertyName("set",$property.name)}(mb);
+        }
+#else##                                               2
+        if ($field != null)
+        {
+#if ($property.isLiteralOnly())##                         3
+#set ($className = $utils.getPrimitiveType($property.className))
+#if ($utils.isPrimitiveClass($className))##               4
+            comp.getAttributes().put("$property.name", ${utils.getBoxedClass($className)}.valueOf($field));
+#else##                                                   4
+            comp.getAttributes().put("$property.name", $field);
+#end##                                                    4
+#else##                                                 3
+            if (isValueReference($field))
+            {
+                ValueBinding vb = context.getApplication().createValueBinding($field);
+                comp.setValueBinding("$property.name", vb);
+            }
+            else
+            {
+#set ($className = $utils.getPrimitiveType($property.className))
+#if ($utils.isPrimitiveClass($className))##               4
+                comp.getAttributes().put("$property.name", ${utils.getBoxedClass($className)}.valueOf($field));
+#else##                                                   4
+                comp.getAttributes().put("$property.name", $field);
+#end##                                                    4
+            }
+#end##                                                  3
+        } 
+#end##                                                2
+#end##                                              1
+    }
+
+    public void release()
+    {
+        super.release();
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#if($utils.getJspPropertyType11($property) == "boolean")
+#set ($empty = "false")
+#else
+#set ($empty = "null")
+#end
+        $field = $empty;
+#end
+    }
+}
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/tagClass12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/tagClass12.vm
new file mode 100644
index 0000000..39daaae
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/tagClass12.vm
@@ -0,0 +1,174 @@
+// WARNING: This file was automatically generated. Do not edit it directly,

+//          or you will lose your changes.

+/*

+ *  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 ${component.tagPackage};

+

+import javax.faces.component.UIComponent;

+import javax.el.ValueExpression;

+import javax.el.MethodExpression;

+import javax.faces.context.FacesContext;

+$utils.importTagClasses12($component)

+

+// Generated from class ${component.sourceClassName}.

+//

+// WARNING: This file was automatically generated. Do not edit it directly,

+//          or you will lose your changes.

+public class $utils.getClassFromFullClass($component.tagClass)

+#if (${component.tagSuperclass})

+    extends ${component.tagSuperclass}

+#else

+    extends javax.faces.webapp.UIComponentTag

+#end

+{

+    public $utils.getClassFromFullClass($component.tagClass)()

+    {    

+    }

+    

+    public String getComponentType()

+    {

+#if ($component.type)

+        return "$component.type";

+#else

+        return null;

+#end

+    }

+

+    public String getRendererType()

+    {

+#if ($component.rendererType && !($component.rendererType == ""))

+        return "$component.rendererType";

+#else

+        return null;

+#end

+    }

+

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

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#set ($type = $utils.getJspPropertyType12($property))

+ 

+    private $type $field;

+    

+#set ($var = $utils.getVariableFromName($property.name))

+    public void $utils.getPrefixedPropertyName("set", $property.jspName)($type $var)

+    {

+        $field = $var;

+    }

+#end

+

+    protected void setProperties(UIComponent component)

+    {

+        if (!(component instanceof $component.className))

+        {

+            throw new IllegalArgumentException("Component "+

+                component.getClass().getName() +" is no $component.className");

+        }

+        

+        $component.className comp = ($component.className) component;

+        

+        super.setProperties(component);

+        

+        FacesContext context = getFacesContext();

+

+#foreach( $property in $propertyList )##            1

+#set ($field = $property.fieldName)

+#set ($type = $utils.getJspPropertyType12($property))

+#if ($utils.isConverter($property.className))##                   2

+        if ($field != null)

+        {

+            if (!${field}.isLiteralText())

+            {

+                comp.setValueExpression("$property.name", $field);

+            }

+            else

+            {

+                String s = ${field}.getExpressionString();

+                if (s != null)

+                {            

+                    Converter converter = getFacesContext().getApplication().createConverter(s);

+                    comp.setConverter(converter);

+                }

+            }

+        }

+#elseif ($property.isMethodBinding())##                 2

+        if ($field != null)

+        {

+#if ($property.jspName == "actionListener")

+            comp.addActionListener(new MethodExpressionActionListener($field));

+#elseif ($property.jspName == "valueChangeListener")

+            comp.addValueChangeListener(new MethodExpressionValueChangeListener($field));

+#elseif ($property.jspName == "validator")

+            comp.addValidator(new MethodExpressionValidator($field));

+#elseif ($utils.isStringMethodBindingReturnType($property.methodBindingSignature))##3

+            MethodBinding mb;

+            if (isValueReference($field))

+            {

+                mb = context.getApplication().createMethodBinding(

+                    $field, $utils.getSignatureParams($property.methodBindingSignature));            

+            }

+            else

+            {

+                throw new IllegalStateException("Invalid expression " + $field);

+            }

+            comp.${utils.getPrefixedPropertyName("set",$property.name)}(mb);

+#else##                                                 3

+            MethodBinding mb = context.getApplication().createMethodBinding(

+                $field, $utils.getSignatureParams($property.methodBindingSignature));

+            comp.${utils.getPrefixedPropertyName("set",$property.name)}(mb);

+#end##                                                  3

+        }

+#elseif ($property.isMethodExpression())##            2

+        if ($field != null)

+        {

+#if ($property.jspName == "action")

+            comp.setActionExpression($field);

+#elseif ($property.jspName == "actionListener")

+            comp.addActionListener(new MethodExpressionActionListener($field));

+#else

+            comp.${utils.getPrefixedPropertyName("set",$property.name)}($field);

+#end        

+        }        

+#else##                                               2

+        if ($field != null)

+        {

+#if ($property.isLiteralOnly())##                         3

+            comp.getAttributes().put("$property.name", $field);

+#else##                                                 3

+            comp.setValueExpression("$property.name", $field);

+#end##                                                  3

+        } 

+#end##                                                2

+#end##                                              1

+    }

+

+    public void release()

+    {

+        super.release();

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#if($utils.getJspPropertyType12($property) == "boolean")

+#set ($empty = "false")

+#else

+#set ($empty = "null")

+#end

+        $field = $empty;

+#end

+    }

+}

diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/tagClassMacros11.vm b/myfaces-builder-plugin/src/main/resources/META-INF/tagClassMacros11.vm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/tagClassMacros11.vm
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/tomahawk12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/tomahawk12.vm
new file mode 100644
index 0000000..4eff9d6
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/tomahawk12.vm
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+ * 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.

+-->

+<taglib xmlns="http://java.sun.com/xml/ns/javaee" 

+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" 

+        version="2.1">

+  <tlib-version>1.1.7</tlib-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>

+#if ($property.isRequired())

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

+#end

+#if ($property.isMethodExpression() || $property.isMethodBinding())

+#if ($property.getMethodBindingSignature())

+        <deferred-method>

+#set ($sig = $property.getMethodBindingSignature())

+            <method-signature>$sig.returnType myMethod( $sig.parameterTypesAsString )</method-signature>

+

+        </deferred-method>

+#else

+## This is a very special case. If a property is MethodBinding or MethodExpression

+## this should have a signature. If not, for allow multiple MethodBinding

+## simulate a ValueExpression and write a custom code like in 

+## org.apache.myfaces.custom.suggestajax.AbstractSuggestAjaxTag

+         <deferred-value/>

+#end

+#elseif ($property.isLiteralOnly())

+         <rtexprvalue>false</rtexprvalue>

+#else

+#set ($type = $utils.getClassFromFullClass($property.className))

+#if ($type == "String")

+         <deferred-value></deferred-value>

+#else

+         <deferred-value>

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

+         </deferred-value>

+#end

+#end

+#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>

+#if ($property.isRequired())

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

+#end

+#if ($property.isLiteralOnly())

+         <rtexprvalue>false</rtexprvalue>

+#else

+#set ($type = $utils.getClassFromFullClass($property.className))

+#if ($type == "String")

+         <deferred-value></deferred-value>

+#else

+         <deferred-value>

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

+         </deferred-value>

+#end

+#end

+#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>

+#if ($property.isRequired())

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

+#end

+#if ($property.isLiteralOnly())

+         <rtexprvalue>false</rtexprvalue>

+#else

+#set ($type = $utils.getClassFromFullClass($property.className))

+#if ($type == "String")

+         <deferred-value></deferred-value>

+#else

+         <deferred-value>

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

+         </deferred-value>

+#end

+#end

+#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>

+#set ($type = $utils.getClassFromFullClass($attribute.className))

+#if ($type == "ValueExpression")

+         <deferred-value></deferred-value>

+#else

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

+#if ($attribute.className)         

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

+#else

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

+#end

+#end

+#if ($property.longDescription)

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

+#else

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

+#end

+      </attribute>

+#end

+   </tag>

+#end

+#end

+</taglib>

diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/validatorClass11.vm b/myfaces-builder-plugin/src/main/resources/META-INF/validatorClass11.vm
new file mode 100644
index 0000000..a5e2a1a
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/validatorClass11.vm
@@ -0,0 +1,222 @@
+## Velocity template used to generate JSF1.1-compatible validator classes

+## from validator meta-data.

+##

+## Note that there are only one type of validator generation:

+##  * "subclass mode" (use annotated class as a parent class)

+##

+## Variable $validator refers to a ValidatorMeta object to process

+## Variable $utils refers to an instance of MyfacesUtils.

+##

+## When "template mode" is being used then variable $innersource

+## holds a String containing all the non-abstract functions defined

+## in the annotated class.

+##

+## The java package of the generated class is always the same as

+## the package in which the annotated class exists.

+##

+/*

+ *  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 ${validator.packageName};

+

+import javax.faces.el.ValueBinding;

+import javax.faces.context.FacesContext;

+$utils.importTagClasses($validator)

+

+#if ($validator.isTemplate())

+#set ($generatedClassParent = $validator.sourceClassParentClassName)

+#else

+#set ($generatedClassParent = $validator.sourceClassName)

+#end

+// Generated from class ${validator.sourceClassName}.

+//

+// WARNING: This file was automatically generated. Do not edit it directly,

+//          or you will lose your changes.

+public class ${utils.getClassFromFullClass($validator.className)} extends $generatedClassParent

+#if ($validator.implements)

+    implements $validator.implements

+#end

+{

+

+#if ($validator.validatorId)

+    static public final String VALIDATOR_ID = 

+        "$validator.validatorId";

+#end

+

+    public ${utils.getClassFromFullClass($validator.className)}()

+    {

+    }

+    

+#set ($propertyList = ${validator.propertyValidatorList})

+

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#set ($type = $utils.getClassFromFullClass($property.className))

+#if($utils.getDefaultValueField($property)) 

+#set ($defaultValue = $utils.getDefaultValueField($property))

+#else

+#set ($defaultValue = false)

+#end

+    // Property: $property.name

+#if ($property.isLiteralOnly() || $property.isTagExcluded() )

+    private $type $field #if($defaultValue) = $defaultValue;#{else};#{end}

+

+     

+#else

+    private $type $field;

+    

+#end

+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded() )

+    private boolean ${field}Set;

+    

+#if ($property.isSetMethod())

+    $property.setMethodScope boolean $utils.getPrefixedPropertyName("isSet", $property.name)()

+    {

+        return ${field}Set;

+    }

+#end

+#end

+#if($property.isLocalMethod())

+#if("boolean" == $type)

+#set ($methodName = $utils.getPrefixedPropertyName("isLocal", $property.name))

+#else

+#set ($methodName = $utils.getPrefixedPropertyName("getLocal", $property.name))

+#end

+    final $property.localMethodScope $type ${methodName}()

+    {

+        return $field;

+    }

+     

+#end

+    public $type $utils.getMethodReaderFromProperty($property.name, $type)()

+    {

+#if ($property.isTagExcluded() || $property.isLiteralOnly())

+        return $field;

+#else

+#if ($utils.isPrimitiveClass($type))

+        if (${field}Set)

+#else

+        if ($field != null)

+#end

+        {

+            return $field;

+        }

+        ValueBinding vb = getValueBinding("$property.name");

+        if (vb != null)

+        {

+#if ($utils.isPrimitiveClass($type))

+            return ($utils.castIfNecessary($type) vb.getValue(getFacesContext())).${type}Value();

+#else

+#set ($pritype = $utils.getPrimitiveType($property.className))

+#if ($utils.isPrimitiveClass($pritype))

+            Object value = vb == null ? null : vb.getValue(getFacesContext());

+            if (!(value instanceof $type)){

+                value = ${type}.valueOf(value.toString());

+            }            

+            return $utils.castIfNecessary($type) value;

+#else

+            return $utils.castIfNecessary($type) vb.getValue(getFacesContext());

+#end

+#end

+        }

+#if ($defaultValue)

+        return $defaultValue; 

+#elseif ($utils.isPrimitiveClass($type))

+        return $utils.primitiveDefaultValue($type);

+#else       

+        return null;

+#end

+#end

+    }

+

+    public void $utils.getPrefixedPropertyName("set", $property.name)($type $utils.getVariableFromName($property.name))

+    {

+        this.$field = $utils.getVariableFromName($property.name);

+#if ($utils.isPrimitiveClass($type) && !$property.isTagExcluded() )

+        this.${field}Set = true;        

+#end

+    }

+#end

+

+    public Object saveState(FacesContext facesContext)

+    {

+#set ($primitiveCount = $propertyList.size() + 1)

+#foreach( $property in $propertyList )

+#if($utils.isPrimitiveClass($property.className))

+#set ($primitiveCount = $primitiveCount + 1)

+#end

+#end

+        Object[] values = new Object[$primitiveCount];

+        values[0] = super.saveState(facesContext);

+#set ($arrayIndex = 0)

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#set ($type = $property.className)

+#set ($arrayIndex = $arrayIndex + 1)

+#if ($property.jspName == "validator" && $property.isMethodBinding() )

+        values[$arrayIndex] = saveAttachedState(facesContext,${field}List);

+#elseif ( $property.isStateHolder() )## || $utils.isConverter($type)

+        values[$arrayIndex] = saveAttachedState(facesContext,$field);

+#elseif($utils.isPrimitiveClass($type))

+#if ($type == "boolean")

+        values[$arrayIndex] = ${utils.getBoxedClass($type)}.valueOf($field);

+#else

+        values[$arrayIndex] = new ${utils.getBoxedClass($type)}($field);

+#end

+#else

+        values[$arrayIndex] = $field;

+#end

+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded())

+#set ($arrayIndex = $arrayIndex + 1)

+        values[$arrayIndex] = Boolean.valueOf(${field}Set);

+#end

+#end

+        return values; 

+    }

+

+    public void restoreState(FacesContext facesContext, Object state)

+    {

+        Object[] values = (Object[])state;

+        super.restoreState(facesContext,values[0]);

+#set ($arrayIndex = 0)

+#foreach( $property in $propertyList )

+#set ($field = $property.fieldName)

+#set ($type = $property.className)

+#set ($arrayIndex = $arrayIndex + 1)

+#if ( $property.isStateHolder() )

+#if ($property.jspName == "validator" && $property.isMethodBinding() )

+        ${field}List = (List<Validator>) restoreAttachedState(facesContext,values[$arrayIndex]);

+#elseif ($utils.isList($type))

+        $field = (List) restoreAttachedState(facesContext,values[$arrayIndex]);

+#else

+        $field = $utils.castIfNecessary($type) restoreAttachedState(facesContext,values[$arrayIndex]); 

+#end

+#elseif ($utils.isConverter($type)) 

+        $field = (Converter) restoreAttachedState(facesContext,values[$arrayIndex]);

+#elseif ($utils.isPrimitiveClass($type))

+        $field = ($utils.castIfNecessary($type) values[$arrayIndex]).${type}Value();

+#else

+        $field = $utils.castIfNecessary($type) values[$arrayIndex];

+#end

+#if($utils.isPrimitiveClass($type) && !$property.isTagExcluded() )

+#set ($arrayIndex = $arrayIndex + 1)

+        ${field}Set = ((Boolean) values[$arrayIndex]).booleanValue();

+#end

+#end

+    }

+}

diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/validatorClassMacros11.vm b/myfaces-builder-plugin/src/main/resources/META-INF/validatorClassMacros11.vm
new file mode 100644
index 0000000..8362de7
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/validatorClassMacros11.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/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-component.vm b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-component.vm
new file mode 100644
index 0000000..33d6ca7
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-component.vm
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>

+<document>

+ <properties>

+  <title>&lt;${component.name}&gt;</title>

+ </properties>

+ <body>

+  <section name="Summary">

+  <p>

+   <b>Tag name:</b> &lt;${component.name}&gt;

+   <br/>

+#set ($javadocPath = "../apidocs/" + $component.getClassName().replace('.', '/') )

+   <b>UIComponent class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${component.className}</a>

+   <br/>

+#if ($component.tagClass)

+#set ($javadocPath = "../apidocs/" + $component.getTagClass().replace('.', '/') )

+   <b>Tag class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${component.tagClass}</a>

+   <br/>

+#end

+   <b>Component type:</b> ${component.type}

+   <br/>

+   <b>Component family:</b> ${component.family}

+   <br/>

+#if (${component.rendererType})

+   <b>Renderer type:</b> ${component.rendererType}

+   <br/>

+#set ($rendererClasses = $tagdocUtils.getRendererClasses($component,$model).values() )

+#foreach ($rendererClass in $rendererClasses)

+#set ($javadocPath = "../apidocs/" + $rendererClass.replace('.', '/') )

+   <b>Renderer class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${rendererClass}</a>

+   <br/>

+#end

+#end

+   <br/>      

+${component.longDescription}   

+  </p>

+  </section>

+#if ($baseContent)

+$baseContent

+#end

+#set($facetList = ${tagdocUtils.getSortedFacetList($component)})

+#if ($facetList.size() != 0)

+  <section name="Supported Facets">

+   <p>

+   <table>

+    <tr>

+     <th>Name</th>

+     <th>Required</th>

+     <th>Description</th>

+    </tr>

+#foreach( $facet in $facetList )

+    <tr>

+     <td>$facet.name</td>

+     <td>$facet.isRequired()</td>

+#if ($facet.longDescription)

+     <td>$facet.longDescription</td>

+#else

+     <td></td>

+#end     

+    </tr>

+#end

+   </table>

+   </p>

+  </section>

+#end  

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

+#if ($propertyList.size() != 0)  

+  <section name="Attributes">

+<table>

+ <tr>

+  <th>Name</th>

+  <th>Type</th>

+  <th>Supports EL?</th>

+  <th>Description</th>

+ </tr>

+#foreach( $property in $propertyList )

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

+ <tr>

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

+#set ($type = ${tagdocUtils.getDisplayType($component.className,$property.jspName,$property.className)})

+  <td>$type</td>

+#if ($property.jspName == "action")

+  <td>Yes</td>

+#elseif ($property.isMethodBinding() || $property.isMethodExpression())

+  <td>Only EL</td>

+#elseif ($property.jspName == "binding")

+  <td>Only EL</td>

+#elseif ($property.isLiteralOnly())

+  <td>No</td>

+#else

+  <td>Yes</td>

+#end

+#if ($property.longDescription)

+  <td>$property.longDescription</td>

+#else

+  <td></td>

+#end

+ </tr>

+#end

+#end

+</table>

+#end

+  </section>

+ </body> 

+</document>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-converter.vm b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-converter.vm
new file mode 100644
index 0000000..5e9ebd6
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-converter.vm
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" ?>

+<document>

+ <properties>

+  <title>&lt;${converter.name}&gt;</title>

+ </properties>

+ <body>

+  <section name="Summary">

+  <p>

+   <b>Tag name:</b> &lt;${converter.name}&gt;

+   <br/>

+#set ($javadocPath = "../apidocs/" + $converter.getClassName().replace('.', '/') )

+   <b>Converter class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${converter.className}</a>

+   <br/>

+#if ($converter.tagClass)

+#set ($javadocPath = "../apidocs/" + $converter.getTagClass().replace('.', '/') )

+   <b>Tag class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${converter.tagClass}</a>

+   <br/>

+#end

+   <b>converter id:</b> ${converter.converterId}

+   <br/>

+${converter.longDescription}   

+  </p>

+  </section>

+#if ($baseContent)

+$baseContent

+#end

+#set ($propertyList = ${tagdocUtils.getSortedPropertyList($converter)})

+#if ($propertyList.size() != 0)  

+  <section name="Attributes">

+<table>

+ <tr>

+  <th>Name</th>

+  <th>Type</th>

+  <th>Supports EL?</th>

+  <th>Description</th>

+ </tr>

+#foreach( $property in $propertyList )

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

+ <tr>

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

+#set ($type = ${tagdocUtils.getDisplayType($converter.className,$property.jspName,$property.className)})

+  <td>$type</td>

+#if ($property.jspName == "action")

+  <td>Yes</td>

+#elseif ($property.isMethodBinding() || $property.isMethodExpression())

+  <td>Only EL</td>

+#elseif ($property.jspName == "binding")

+  <td>Only EL</td>

+#elseif ($property.isLiteralOnly())

+  <td>No</td>

+#else

+  <td>Yes</td>

+#end

+#if ($property.longDescription)

+  <td>$property.longDescription</td>

+#else

+  <td></td>

+#end

+ </tr>

+#end

+#end

+</table>

+#end

+  </section>

+ </body> 

+</document>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-tag.vm b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-tag.vm
new file mode 100644
index 0000000..65e42cf
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-tag.vm
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>

+<document>

+ <properties>

+  <title>&lt;${tag.name}&gt;</title>

+ </properties>

+ <body>

+  <section name="Summary">

+  <p>

+   <b>Tag name:</b> &lt;${tag.name}&gt;

+   <br/>

+#set ($javadocPath = "../apidocs/" + $tag.getClassName().replace('.', '/') )

+   <b>Tag class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${tag.className}</a>

+   <br/>

+${tag.longDescription}   

+  </p>

+  </section>

+#if ($baseContent)

+$baseContent

+#end

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

+#if ($attributeList.size() != 0)  

+  <section name="Attributes">

+<table>

+ <tr>

+  <th>Name</th>

+  <th>Type</th>

+  <th>Required</th>

+  <th>Description</th>

+ </tr>

+#foreach( $attribute in $attributeList )

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

+ <tr>

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

+#set ($type = ${tagdocUtils.getDisplayType($tag.className,$attribute.name,$attribute.className)})

+  <td>$type</td>

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

+#if ($attribute.longDescription)

+  <td>$attribute.longDescription</td>

+#else

+  <td></td>

+#end

+ </tr>

+#end

+#end

+</table>

+#end

+  </section>

+ </body> 

+</document>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-validator.vm b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-validator.vm
new file mode 100644
index 0000000..fbf928b
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/xdoc-validator.vm
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" ?>

+<document>

+ <properties>

+  <title>&lt;${validator.name}&gt;</title>

+ </properties>

+ <body>

+  <section name="Summary">

+  <p>

+   <b>Tag name:</b> &lt;${validator.name}&gt;

+   <br/>

+#set ($javadocPath = "../apidocs/" + $validator.getClassName().replace('.', '/') )

+   <b>Validator class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${validator.className}</a>

+   <br/>

+#if ($validator.tagClass)

+#set ($javadocPath = "../apidocs/" + $validator.getTagClass().replace('.', '/') )

+   <b>Tag class:</b> <a href="${tagdocUtils.platformAgnosticPath( $javadocPath )}.html">${validator.tagClass}</a>

+   <br/>

+#end

+   <b>validator id:</b> ${validator.validatorId}

+   <br/>

+${validator.longDescription}   

+  </p>

+  </section>

+#if ($baseContent)

+$baseContent

+#end

+#set ($propertyList = ${tagdocUtils.getSortedPropertyList($validator)})

+#if ($propertyList.size() != 0)  

+  <section name="Attributes">

+<table>

+ <tr>

+  <th>Name</th>

+  <th>Type</th>

+  <th>Supports EL?</th>

+  <th>Description</th>

+ </tr>

+#foreach( $property in $propertyList )

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

+ <tr>

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

+#set ($type = ${tagdocUtils.getDisplayType($validator.className,$property.jspName,$property.className)})

+  <td>$type</td>

+#if ($property.jspName == "action")

+  <td>Yes</td>

+#elseif ($property.isMethodBinding() || $property.isMethodExpression())

+  <td>Only EL</td>

+#elseif ($property.jspName == "binding")

+  <td>Only EL</td>

+#elseif ($property.isLiteralOnly())

+  <td>No</td>

+#else

+  <td>Yes</td>

+#end

+#if ($property.longDescription)

+  <td>$property.longDescription</td>

+#else

+  <td></td>

+#end

+ </tr>

+#end

+#end

+</table>

+#end

+  </section>

+ </body> 

+</document>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/xmlMacros.vm b/myfaces-builder-plugin/src/main/resources/META-INF/xmlMacros.vm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/xmlMacros.vm
diff --git a/myfaces-builder-plugin/src/site/apt/howto.apt b/myfaces-builder-plugin/src/site/apt/howto.apt
new file mode 100644
index 0000000..dfe74af
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/howto.apt
@@ -0,0 +1,40 @@
+ ~~ 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.
+
+ ------
+ Myfaces Builder Plugin 
+ ------
+
+How to Use
+
+  A quick summary of how to use the plugin...
+  
+-------------------
+<project>
+   ...
+      <build>
+         ...
+        <plugins>
+            <plugin>
+                <groupId>org.apache.myfaces.buildtools</groupId>
+                <artifactId>myfaces-builder-plugin</artifactId>
+             </plugin>
+         </plugins>
+         ...
+      </build>
+   ...
+</project>
+-------------------
+
diff --git a/myfaces-builder-plugin/src/site/apt/index.apt b/myfaces-builder-plugin/src/site/apt/index.apt
new file mode 100644
index 0000000..c7fe610
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/index.apt
@@ -0,0 +1,167 @@
+ ~~ 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.
+
+ ------
+ Myfaces Builder Plugin 
+ ------
+ 
+Summary
+
+  This is a maven plugin that uses javadoc annotations to generate the necessary JSF configuration
+  files (.tld, faces-config.xml, etc) and optionally Tag, Validator and Component classes.
+
+  See the documentation menu in the left-hand navigation pane for more information.
+
+Introduction
+
+  A JSF component library needs to provide hand-written:
+
+  * component classes
+  
+  * renderer classes
+
+  * converter and validator classes
+    
+  []
+
+  It then needs to also provide:
+
+  * jsp taglib files
+
+  * facelets taglib files
+
+  * tag classes
+  
+  []
+
+  However in most cases, the second category of artifacts can be generated from the
+  first ones. Tag classes generally just copy data from one format to another and
+  do not have any custom logic; they can effectively be created using code templates.
+  The config files are mostly just a "summary" of the information in the hand-written
+  classes above, and so are also a candidate for generation.
+
+  In addition, components have a lot of getter/setter methods for properties, where the
+  getter/setter implementations are very repetitive. Components also need to provide
+  state-handling methods (saveState/restoreState) which are also repetitive. In both
+  cases, the necessary methods can potentially be generated given metadata about the
+  properties belonging to a component. 
+  
+Requirements
+
+  * Minimise the amount of code duplication, ie where a single change requires changes
+    in two different places
+
+  * Minimise bugs due to inconsistencies between data that should match.
+  
+  * Reduce the boredom factor
+  
+  * Allow optimisations in handling of JSF classes (eg state-saving improvements) to
+    be implemented in just one place, rather than having to repeat the same fix in
+    every place that uses the same boilerplate code.
+    
+  * Keep the code simple to understand for people new to MyFaces. A solution that will
+    discourage people from committing patches to myfaces code is worse than no solution.
+
+  * Don't make building the code more complicated.
+
+  * Don't make debugging of the code more complicated
+
+  * Provide a solution that can be applied to as many myfaces projects as possible;
+    a separate build tool per project is not desirable. Note, however, that each
+    project must "opt in", so any successful tool must satisfy the needs of multiple
+    projects, or be sufficiently extensible for other projects to extend it to match.
+
+  * Allow external code to subclass components that are within a project which has
+    been built by the myfaces-builder-plugin. MyFaces components are meant to be
+    used as a base for other code; it would be nice to be able to offer a build tool
+    that users can apply to their own code when extending myfaces classes in order
+    to inherit the same metadata.   
+  
+Gathering and saving meta-data
+
+  In order to drive all of the above artifact generation, metadata about the artifacts
+  to be generated is needed. There are several reasonable ways to gather this info.
+  
+  * For several years, Trinidad has used xml files to declare the necessary data.
+  
+  * The Tobago project uses java1.5 annotations (with compile-scope retention) plus
+    introspection of the classes (via the apt tool and the com.sun.mirror api) to
+    derive the necessary data.
+  
+  * The use of javadoc annotations for metadata (eg xdoclet) also has a long successful
+    history as a way to represent metadata.
+
+  []
+  
+  In addition, people will no doubt invent other solutions in the future.
+  
+  Therefore, the myfaces-builder-plugin provides "pluggable" metadata gathering in order
+  for different projects to represent their metadata as they wish. In fact, it should
+  support "chaining" of metadata gathering, so that part of the data can be gathered one
+  way, and part of it another way.
+  
+  After a project using the myfaces-builder-plugin is published, people can then derive
+  their own components from the classes in the published jarfile. They can always implement
+  their own solution for defining the necessary tag classes, config files, etc. However it
+  would be nice to allow this plugin to also be usable on that external code. And in fact
+  this same issue also occurs internally within myfaces, eg between the -api and -impl jars
+  of a JSF implementation. There are a number of possible solutions, but the one chosen is
+  for myfaces-builder-plugin to generate a .xml file containing the metadata it has gathered
+  about a project, and for this file to be published in the META-INF directory of each 
+  jarfile. This file can then be used as another source of meta-data by the builder plugin
+  itself; ie if the builder has built project A, then it can use the file it left in the
+  META-INF of A.jar in order to help build components that extend the classes in A.
+  
+Generating output
+
+  The whole point of the artifacts being generated (config files or java code) is that they
+  are very repetitive internally, varying only due to the metadata information. Therefore
+  a templating mechanism should be used to generate these.
+  
+  However there are a large number of possible templating solutions. In addition, the
+  trinidad plugin has a history of generating output via hard-coding print statements in
+  java rather than using templating.
+  
+  The builder plugin therefore also provides a "pluggable" generation mechanism, so that
+  projects can customise the process as they need. 
+  
+  Initially, builder will support the org.antlr.StringTemplate library as the template
+  mechanism, mainly because that is what Tobago currently uses. However there is no
+  reason why other approaches cannot be used.
+  
+Representing MetaData internally
+
+  Classes in the "model" package store all the metadata that can be gathered. The model is
+  therefore the union of all data needed by all supported projects. 
+  
+  The model objects are created/populated by the model-builders, and then used by the
+  various generator modules.
+  
+  The metadata itself can be written to xml and read back from xml. This allows the following:
+  
+  * the task of gathering the metadata can be one maven goal, with output being a file.
+
+  * the task of generating artfacts from metadata can just read the previously-created metadata
+    file without repeating the data-gathering process.
+    
+  []
+
+  It also means that:
+      
+  * metadata can be stored in a file in the META-INF of a published jar
+
+  * the builder plugin can re-read the file from the META-INF of a published jar, allowing
+    libraries to easily *extend* classes declared in a published jar and still have access
+    to the metadata for those ancestor classes.  ------
diff --git a/myfaces-builder-plugin/src/site/site.xml b/myfaces-builder-plugin/src/site/site.xml
new file mode 100644
index 0000000..ca96b38
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/site.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<project name="Myfaces Builder Plugin">
+  <bannerLeft>
+    <name>Apache MyFaces</name>
+    <src>img/banners/MyFaces_logo.jpg</src>
+    <href>http://myfaces.apache.org/index.html</href>
+  </bannerLeft>
+
+  <bannerRight>
+    <name>Apache Banner</name>
+    <src>img/banners/apache_banner.png</src>
+    <href>http://www.apache.org/</href>
+  </bannerRight>  
+
+  <publishDate format="dd MMM yyyy"/>
+
+  <skin>
+    <groupId>org.apache.myfaces.maven</groupId>
+    <artifactId>myfaces-site-skin</artifactId>
+    <version>1-SNAPSHOT</version>
+  </skin>
+
+
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org"/>
+      <item name="MyFaces" href="http://myfaces.apache.org/index.html"/>
+    </links>
+
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="How to Use" href="howto.html"/>
+    </menu>
+
+    <menu ref="reports"/>
+
+  </body>
+</project>
diff --git a/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojoTest.java b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojoTest.java
new file mode 100644
index 0000000..9388e13
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojoTest.java
@@ -0,0 +1,55 @@
+/*
+ *  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 junit.framework.TestCase;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyMeta;
+
+/**
+ * Tests the faces-config.xml generation mojo.
+ */
+public class BuildMetaDataMojoTest extends TestCase
+{
+    public void testWrite() throws Exception
+    {
+        Model model = new Model();
+
+        ComponentMeta comp = new ComponentMeta();
+        comp.setName("mockComponent");
+        comp.setClassName("example.MockComponent");
+        comp.setDescription("dummy desc");
+        comp.setLongDescription("dummy long desc");
+        comp.setFamily("mockFamily");
+        comp.setParentClassName("javax.faces.UIComponent");
+        comp.setType("mockType");
+
+        PropertyMeta prop = new PropertyMeta();
+        prop.setName("mockProp");
+        prop.setDescription("propdesc");
+        prop.setLiteralOnly(Boolean.TRUE);
+        prop.setRequired(Boolean.TRUE);
+        comp.addProperty(prop);
+
+        model.addComponent(comp);
+
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/FlattenerTest.java b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/FlattenerTest.java
new file mode 100644
index 0000000..8a58f00
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/FlattenerTest.java
@@ -0,0 +1,160 @@
+/*
+ *  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.BufferedReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+
+/**
+ * Test flattening of a model.
+ */
+public class FlattenerTest extends TestCase
+{
+    /**
+     * Load the "goodfile.xml" from the complex test case, flattens it and
+     * then compares the result to an expected good file.
+     */
+    public void testComplex() throws Exception
+    {
+        ClassLoader classLoader = this.getClass().getClassLoader();
+
+        InputStream is = classLoader
+                .getResourceAsStream("builder/complex/goodfile.xml");
+        String orig = readAll(is);
+        is.close();
+
+        Model model = IOUtils.readModel(new StringReader(orig));
+
+        new Flattener(model).flatten();
+        
+        StringWriter dstWriter = new StringWriter();
+        IOUtils.writeModel(model, dstWriter);
+        String dst = dstWriter.toString();
+
+        // Dump the output to disk, to help debugging if something fails
+        writeAll("target/complex-flat.xml", dst);
+        
+        // now load goodfile-flat.xml and check that it is as expected
+        InputStream is2 = classLoader
+                .getResourceAsStream("builder/complex/goodfile-flat.xml");
+        compareData(new StringReader(dst), new InputStreamReader(is2));
+        is2.close();
+    }
+
+    /**
+     * Load the "goodfile.xml" from the generation test case, flattens it and
+     * then compares the result to an expected good file.
+     */
+    public void testGeneration() throws Exception
+    {
+        ClassLoader classLoader = this.getClass().getClassLoader();
+
+        InputStream is = classLoader
+                .getResourceAsStream("builder/generation/goodfile.xml");
+        String orig = readAll(is);
+        is.close();
+
+        Model model = IOUtils.readModel(new StringReader(orig));
+
+        new Flattener(model).flatten();
+        
+        StringWriter dstWriter = new StringWriter();
+        IOUtils.writeModel(model, dstWriter);
+        String dst = dstWriter.toString();
+
+        // Dump the output to disk, to help debugging if something fails
+        writeAll("target/generation-flat.xml", dst);
+        
+        // now load goodfile-flat.xml and check that it is as expected
+        InputStream is2 = classLoader
+                .getResourceAsStream("builder/generation/goodfile-flat.xml");
+        compareData(new StringReader(dst), new InputStreamReader(is2));
+        is2.close();
+    }
+
+    /**
+     * Read the contents of an input stream into a string.
+     */
+    private String readAll(InputStream is) throws IOException
+    {
+        InputStreamReader reader = new InputStreamReader(is);
+        StringBuffer out = new StringBuffer(4096);
+        char[] buf = new char[1024];
+        while (true)
+        {
+            int nchars = reader.read(buf);
+            if (nchars <= 0)
+            {
+                break;
+            }
+            out.append(buf, 0, nchars);
+        }
+        return out.toString();
+    }
+
+    private void writeAll(String dstFile, String src) throws Exception
+    {
+        FileWriter fw = new FileWriter(dstFile);
+        fw.write(src);
+        fw.close();
+    }
+
+    /**
+     * Compare the contents of two Reader objects line-by-line.
+     */
+    private void compareData(Reader src1, Reader src2) throws IOException
+    {
+        BufferedReader in1 = new BufferedReader(src1);
+        BufferedReader in2 = new BufferedReader(src2);
+
+        int line = 0;
+        for (;;)
+        {
+            ++line;
+            String line1 = in1.readLine();
+            String line2 = in2.readLine();
+
+            if ((line1 == null) && (line2 == null))
+            {
+                // success
+                return;
+            }
+            else if (line1 == null)
+            {
+                fail("input 2 has more lines than input 1");
+            }
+            else if (line2 == null)
+            {
+                fail("input 1 has more lines than input 2");
+            }
+
+            assertEquals("Inputs differ on line " + line, line1, line2);
+        }
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtilsTest.java b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtilsTest.java
new file mode 100644
index 0000000..dd304f6
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtilsTest.java
@@ -0,0 +1,124 @@
+/*
+ *  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.BufferedReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+
+/**
+ * Tests saving and loading models from xml.
+ */
+public class IOUtilsTest extends TestCase
+{
+    /**
+     * Load the "goodfile.xml" from the complex test case and build a Model
+     * object from it, then save it again and compare to the original.
+     */
+    public void testComplex() throws Exception
+    {
+        ClassLoader classLoader = this.getClass().getClassLoader();
+
+        InputStream is = classLoader
+                .getResourceAsStream("builder/complex/goodfile.xml");
+        String src = readAll(is);
+        is.close();
+
+        StringReader srcReader = new StringReader(src);
+        Model model = IOUtils.readModel(srcReader);
+
+        StringWriter dstWriter = new StringWriter();
+        IOUtils.writeModel(model, dstWriter);
+        String dst = dstWriter.toString();
+        writeAll("target/outfile-ioutils.xml", dst);
+
+        srcReader = new StringReader(src);
+        StringReader dstReader = new StringReader(dst);
+        compareData(srcReader, dstReader);
+    }
+
+    /**
+     * Read the contents of an input stream into a string.
+     */
+    private String readAll(InputStream is) throws IOException
+    {
+        InputStreamReader reader = new InputStreamReader(is);
+        StringBuffer out = new StringBuffer(4096);
+        char[] buf = new char[1024];
+        while (true)
+        {
+            int nchars = reader.read(buf);
+            if (nchars <= 0)
+            {
+                break;
+            }
+            out.append(buf, 0, nchars);
+        }
+        return out.toString();
+    }
+
+    private void writeAll(String dstFile, String src) throws Exception
+    {
+        FileWriter fw = new FileWriter(dstFile);
+        fw.write(src);
+        fw.close();
+    }
+
+    /**
+     * Compare the contents of two Reader objects line-by-line.
+     */
+    private void compareData(Reader src1, Reader src2) throws IOException
+    {
+        BufferedReader in1 = new BufferedReader(src1);
+        BufferedReader in2 = new BufferedReader(src2);
+
+        int line = 0;
+        for (;;)
+        {
+            ++line;
+            String line1 = in1.readLine();
+            String line2 = in2.readLine();
+
+            if ((line1 == null) && (line2 == null))
+            {
+                // success
+                return;
+            }
+            else if (line1 == null)
+            {
+                fail("input 2 has more lines than input 1");
+            }
+            else if (line2 == null)
+            {
+                fail("input 1 has more lines than input 2");
+            }
+
+            assertEquals("Inputs differ on line " + line, line1, line2);
+        }
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeComponentsMojoTest.java b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeComponentsMojoTest.java
new file mode 100644
index 0000000..d708d84
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeComponentsMojoTest.java
@@ -0,0 +1,42 @@
+/*
+ *  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 junit.framework.TestCase;
+
+/**
+ * Tests the component generation mojo
+ */
+public class MakeComponentsMojoTest extends TestCase
+{
+    public void testCleanInitializerExpression() throws Exception
+    {
+        String badExpr =
+            "  // some stuff\n" +
+            "\n"
+            + "  true";
+
+        String cleaned = MakeComponentsMojo.cleanInitializationExpression(badExpr);
+        String good = "true";
+        assertEquals(good, cleaned);
+        
+        assertEquals(null, MakeComponentsMojo.cleanInitializationExpression("  "));
+        assertEquals(null, MakeComponentsMojo.cleanInitializationExpression("  // blah"));
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilderTest.java b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilderTest.java
new file mode 100644
index 0000000..22b9f70
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilderTest.java
@@ -0,0 +1,267 @@
+/*
+ *  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.qdox;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyMeta;
+
+/**
+ * Tests the QDoxModelBuilderTest generation mojo.
+ */
+public class QdoxModelBuilderTest extends TestCase
+{
+    public void testMethodToPropName() throws Exception
+    {
+        assertEquals("fooBar", QdoxModelBuilder.methodToPropName("getfooBar"));
+        assertEquals("fooBar", QdoxModelBuilder.methodToPropName("getFooBar"));
+        assertEquals("url", QdoxModelBuilder.methodToPropName("getUrl"));
+        assertEquals("url", QdoxModelBuilder.methodToPropName("getURL"));
+        assertEquals("urlLocation", QdoxModelBuilder
+                .methodToPropName("getUrlLocation"));
+        assertEquals("urlLocation", QdoxModelBuilder
+                .methodToPropName("getURLLocation"));
+    }
+
+    public void testScan() throws Exception
+    {
+        QdoxModelBuilder builder = new QdoxModelBuilder();
+        Model model = new Model();
+        model.setModelId("test");
+
+        URL sourceUrl = this.getClass().getClassLoader().getResource(
+                "builder/simple/Foo.java");
+        String parentDirName = new File(sourceUrl.getFile()).getParent();
+        File parentDir = new File(parentDirName);
+        List sourceDirs = new ArrayList();
+        sourceDirs.add(parentDir.getAbsolutePath());
+        builder.buildModel(model, sourceDirs);
+
+        assertEquals(1, model.getComponents().size());
+        ComponentMeta cm = (ComponentMeta) model.getComponents().get(0);
+        assertEquals(1, cm.propertiesSize());
+        Iterator props = cm.properties();
+        PropertyMeta prop1 = (PropertyMeta) props.next();
+        assertEquals("prop1", prop1.getName());
+        assertEquals("java.lang.String", prop1.getClassName());
+    }
+
+    /**
+     * Scan a very simple source tree, and compare the result (line by line)
+     * against a "known good" file.
+     */
+    public void testSimple() throws Exception
+    {
+        QdoxModelBuilder builder = new QdoxModelBuilder();
+
+        ClassLoader classLoader = this.getClass().getClassLoader();
+        URL sourceUrl = classLoader.getResource("builder/simple/Foo.java");
+        String parentDirName = new File(sourceUrl.getFile()).getParent();
+        File parentDir = new File(parentDirName);
+        List sourceDirs = new ArrayList();
+        sourceDirs.add(parentDir.getAbsolutePath());
+
+        Model model = new Model();
+        model.setModelId("test");
+        builder.buildModel(model, sourceDirs);
+
+        // basic sanity checks
+        assertTrue(model.getComponents().size() > 0);
+
+        // Now write it. Optionally, we could just write it to an in-memory
+        // buffer.
+        File outfile = new File("target/simple-out.xml");
+        IOUtils.saveModel(model, outfile);
+
+        StringWriter outbuf = new StringWriter();
+        IOUtils.writeModel(model, outbuf);
+
+        compareData(outfile, "builder/simple/goodfile.xml");
+    }
+
+    /**
+     * Scan a very simple source tree that uses java15 annotations, and compare
+     * the result (line by line) against a "known good" file.
+     */
+    public void testSimple15() throws Exception
+    {
+        QdoxModelBuilder builder = new QdoxModelBuilder();
+
+        ClassLoader classLoader = this.getClass().getClassLoader();
+        URL sourceUrl = classLoader.getResource("builder/simple15/Foo.java");
+        String parentDirName = new File(sourceUrl.getFile()).getParent();
+        File parentDir = new File(parentDirName);
+        List sourceDirs = new ArrayList();
+        sourceDirs.add(parentDir.getAbsolutePath());
+
+        Model model = new Model();
+        model.setModelId("test");
+        builder.buildModel(model, sourceDirs);
+
+        // basic sanity checks
+        assertTrue(model.getComponents().size() > 0);
+
+        // Now write it. Optionally, we could just write it to an in-memory
+        // buffer.
+        File outfile = new File("target/simple15-out.xml");
+        IOUtils.saveModel(model, outfile);
+
+        StringWriter outbuf = new StringWriter();
+        IOUtils.writeModel(model, outbuf);
+
+        compareData(outfile, "builder/simple15/goodfile.xml");
+    }
+
+    /**
+     * Scan annotated JSFComponent classes which use code-generation to 
+     * actually create component classes.
+     */
+    public void testGeneration() throws Exception
+    {
+        QdoxModelBuilder builder = new QdoxModelBuilder();
+
+        ClassLoader classLoader = this.getClass().getClassLoader();
+        URL sourceUrl = classLoader
+                .getResource("builder/generation/testpkg/ComponentBase.java");
+        String parentDirName = new File(sourceUrl.getFile()).getParent();
+        File parentDir = new File(parentDirName);
+        File baseDir = parentDir.getParentFile();
+        List sourceDirs = new ArrayList();
+        sourceDirs.add(baseDir.getAbsolutePath());
+
+        Model model = new Model();
+        model.setModelId("test");
+        builder.buildModel(model, sourceDirs);
+
+        // basic sanity checks
+        assertTrue(model.getComponents().size() > 0);
+
+        // Now write it. Optionally, we could just write it to an in-memory
+        // buffer.
+        File outfile = new File("target/generation-out.xml");
+        IOUtils.saveModel(model, outfile);
+
+        StringWriter outbuf = new StringWriter();
+        IOUtils.writeModel(model, outbuf);
+
+        compareData(outfile, "builder/generation/goodfile.xml");
+    }
+
+    /**
+     * Scan a very complex source tree, containing all the different features in
+     * various combinations, then dump the result to a file and compare it (line
+     * by line) against a "known good" file.
+     */
+    public void testComplex() throws Exception
+    {
+        QdoxModelBuilder builder = new QdoxModelBuilder();
+
+        ClassLoader classLoader = this.getClass().getClassLoader();
+        URL sourceUrl = classLoader
+                .getResource("builder/complex/ComponentBase.java");
+        String parentDirName = new File(sourceUrl.getFile()).getParent();
+        File parentDir = new File(parentDirName);
+        List sourceDirs = new ArrayList();
+        sourceDirs.add(parentDir.getAbsolutePath());
+
+        Model model = new Model();
+        model.setModelId("test");
+        builder.buildModel(model, sourceDirs);
+
+        // basic sanity checks
+        assertTrue(model.getComponents().size() > 0);
+
+        // Now write it. Optionally, we could just write it to an in-memory
+        // buffer.
+        File outfile = new File("target/complex-out.xml");
+        IOUtils.saveModel(model, outfile);
+
+        StringWriter outbuf = new StringWriter();
+        IOUtils.writeModel(model, outbuf);
+
+        compareData(outfile, "builder/complex/goodfile.xml");
+    }
+
+    /**
+     * Compare the contents of two Reader objects line-by-line.
+     */
+    private void compareData(File testDatafileName, String goodResourceName) throws IOException
+    {
+        Reader testDataReaderRaw = new FileReader(testDatafileName);
+
+        ClassLoader classLoader = this.getClass().getClassLoader();
+        InputStream goodDataStream = classLoader.getResourceAsStream(goodResourceName);
+        assertNotNull("good resource file not found: " + goodResourceName, goodDataStream);
+        Reader goodDataReaderRaw = new InputStreamReader(goodDataStream);
+
+        BufferedReader testDataReader = new BufferedReader(testDataReaderRaw);
+        BufferedReader goodDataReader = new BufferedReader(goodDataReaderRaw);
+
+        try
+        {
+            int line = 0;
+            for (;;)
+            {
+                ++line;
+                String testLine = testDataReader.readLine();
+                String goodLine = goodDataReader.readLine();
+    
+                if ((testLine == null) && (goodLine == null))
+                {
+                    // success
+                    break;
+                }
+                else if (testLine == null)
+                {
+                    fail("Test input " + testDatafileName + " has fewer lines than good file " + goodResourceName);
+                }
+                else if (goodLine == null)
+                {
+                    fail("Test input " + testDatafileName + " has more lines than good file " + goodResourceName);
+                }
+    
+                assertEquals(
+                        "Test input " + testDatafileName + " and good file " + goodResourceName +
+                        " differ on line " + line, 
+                        goodLine, testLine);
+            }
+        }
+        finally
+        {
+            testDataReaderRaw.close();
+            goodDataStream.close();
+        }
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentBase.java b/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentBase.java
new file mode 100644
index 0000000..775bdd4
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentBase.java
@@ -0,0 +1,24 @@
+/**
+ * A base component class.
+ * <p>
+ * This is a base component. It has no name, so is not a concrete component.
+ * 
+ * @JSFComponent
+ *   type="base"
+ *   family="base"
+ *   defaultRendererType="BaseRenderer"
+ */
+
+public abstract class ComponentBase
+{
+    /**
+     * The prop1 property.
+     * <p>
+     * Some dummy prop1 documentation.
+     *
+     * @JSFProperty
+     */
+    public abstract String getProp1();
+    
+    public abstract void setProp1(String prop1);
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentChild.java b/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentChild.java
new file mode 100644
index 0000000..0fca1a2
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentChild.java
@@ -0,0 +1,61 @@
+/**
+ * The ComponentChild component.
+ * <p>
+ * This is a child component. It does nothing useful.
+ * 
+ * @JSFComponent
+ *   name="foo"
+ *   type="foo"
+ *   family="foo"
+ *   defaultRendererType="FooRenderer"
+ */
+public class ComponentChild extends ComponentBase implements ComponentInterface
+{
+    String prop1;
+    boolean prop2;
+    
+    /**
+     * Implement the abstract property defined on the base class.
+     * Note that because this method is not annotated with the
+     * JSFProperty annotation, this comment does not become the
+     * documentation for the property itself.
+     */
+    public String getProp1()
+    {
+        return prop1;
+    }
+
+    public void setProp1(String prop1)
+    {
+        this.prop1 = prop1;
+    }
+
+    /**
+     * The prop2 property.
+     * <p>
+     * Some dummy prop2 documentation.
+     *
+     * @JSFProperty
+     */
+    public boolean getProp2() {
+        return prop2;
+    }
+    
+    public void setProp2(boolean prop2) {
+        this.prop2 = prop2;
+    }
+
+    /**
+     * Implement the method defined on ComponentInterface. Because this method does
+     * not use the JSFProperty annotation, the property settings are taken from the
+     * parent interface, not here.
+     */
+    public String getIfaceProp()
+    {
+        return null;
+    }
+
+    public void setIfaceProp(String val)
+    {
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentInterface.java b/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentInterface.java
new file mode 100644
index 0000000..c26b52b
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/complex/ComponentInterface.java
@@ -0,0 +1,24 @@
+/**
+ * An interface that defines component properties.
+ * <p>
+ * This is an interface component.
+ * 
+ * @JSFComponent
+ *   type="iface"
+ *   family="iface"
+ *   defaultRendererType="BaseRenderer"
+ */
+
+public interface ComponentInterface
+{
+    /**
+     * The ifaceProp property.
+     * <p>
+     * Some dummy ifaceProp documentation.
+     *
+     * @JSFProperty
+     */
+    String getIfaceProp();
+    
+    void setIfaceProp(String val);
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/complex/Converter1.java b/myfaces-builder-plugin/src/test/resources/builder/complex/Converter1.java
new file mode 100644
index 0000000..2687628
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/complex/Converter1.java
@@ -0,0 +1,11 @@
+/**
+ * The Converter1 converter.
+ * <p>
+ * This is a silly converter. It does nothing useful.
+ * 
+ * @JSFConverter id="conv1"
+ */
+public class Converter1 // implements Converter
+{
+    // TODO: converters can have properties too
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/complex/Validator1.java b/myfaces-builder-plugin/src/test/resources/builder/complex/Validator1.java
new file mode 100644
index 0000000..0464aba
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/complex/Validator1.java
@@ -0,0 +1,11 @@
+/**
+ * The Validator1 validator.
+ * <p>
+ * This is a silly validator. It does nothing useful.
+ * 
+ * @JSFValidator id="val1"
+ */
+public class Validator1 // implements Validator
+{
+    // TODO: validators can have properties too
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/complex/goodfile-flat.xml b/myfaces-builder-plugin/src/test/resources/builder/complex/goodfile-flat.xml
new file mode 100644
index 0000000..5904dca
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/complex/goodfile-flat.xml
@@ -0,0 +1,151 @@
+<?xml version='1.0' ?>
+
+<model>
+  <modelId>test</modelId>
+  <component>
+    <modelId>test</modelId>
+    <className>ComponentBase</className>
+    <sourceClassName>ComponentBase</sourceClassName>
+    <type>base</type>
+    <family>base</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>A base component class</desc>
+    <longDesc>
+<![CDATA[
+A base component class.
+<p>
+This is a base component. It has no name, so is not a concrete component.
+]]>
+    </longDesc>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <generated>true</generated>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>ComponentInterface</className>
+    <sourceClassName>ComponentInterface</sourceClassName>
+    <type>iface</type>
+    <family>iface</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>An interface that defines component properties</desc>
+    <longDesc>
+<![CDATA[
+An interface that defines component properties.
+<p>
+This is an interface component.
+]]>
+    </longDesc>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>ComponentChild</className>
+    <parentClassName>ComponentBase</parentClassName>
+    <sourceClassName>ComponentChild</sourceClassName>
+    <sourceClassParentClassName>ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="ComponentInterface"/>
+    </interfaces>
+    <name>foo</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <desc>The ComponentChild component</desc>
+    <longDesc>
+<![CDATA[
+The ComponentChild component.
+<p>
+This is a child component. It does nothing useful.
+]]>
+    </longDesc>
+    <property>
+      <name>prop2</name>
+      <className>boolean</className>
+      <desc>The prop2 property</desc>
+      <longDesc>
+<![CDATA[
+The prop2 property.
+<p>
+Some dummy prop2 documentation.
+]]>
+      </longDesc>
+    </property>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+      <generated>true</generated>
+    </property>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+    </property>
+  </component>
+  <converter>
+    <modelId>test</modelId>
+    <className>Converter1</className>
+    <sourceClassName>Converter1</sourceClassName>
+    <converterId>conv1</converterId>
+    <desc>The Converter1 converter</desc>
+    <longDesc>
+<![CDATA[
+The Converter1 converter.
+<p>
+This is a silly converter. It does nothing useful.
+]]>
+    </longDesc>
+  </converter>
+  <validator>
+    <modelId>test</modelId>
+    <className>Validator1</className>
+    <sourceClassName>Validator1</sourceClassName>
+    <validatorId>val1</validatorId>
+    <desc>The Validator1 validator</desc>
+    <longDesc>
+<![CDATA[
+The Validator1 validator.
+<p>
+This is a silly validator. It does nothing useful.
+]]>
+    </longDesc>
+  </validator>
+</model>
diff --git a/myfaces-builder-plugin/src/test/resources/builder/complex/goodfile.xml b/myfaces-builder-plugin/src/test/resources/builder/complex/goodfile.xml
new file mode 100644
index 0000000..deb3f61
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/complex/goodfile.xml
@@ -0,0 +1,124 @@
+<?xml version='1.0' ?>
+
+<model>
+  <modelId>test</modelId>
+  <component>
+    <modelId>test</modelId>
+    <className>ComponentBase</className>
+    <sourceClassName>ComponentBase</sourceClassName>
+    <type>base</type>
+    <family>base</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>A base component class</desc>
+    <longDesc>
+<![CDATA[
+A base component class.
+<p>
+This is a base component. It has no name, so is not a concrete component.
+]]>
+    </longDesc>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <generated>true</generated>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>ComponentInterface</className>
+    <sourceClassName>ComponentInterface</sourceClassName>
+    <type>iface</type>
+    <family>iface</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>An interface that defines component properties</desc>
+    <longDesc>
+<![CDATA[
+An interface that defines component properties.
+<p>
+This is an interface component.
+]]>
+    </longDesc>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>ComponentChild</className>
+    <parentClassName>ComponentBase</parentClassName>
+    <sourceClassName>ComponentChild</sourceClassName>
+    <sourceClassParentClassName>ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="ComponentInterface"/>
+    </interfaces>
+    <name>foo</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <desc>The ComponentChild component</desc>
+    <longDesc>
+<![CDATA[
+The ComponentChild component.
+<p>
+This is a child component. It does nothing useful.
+]]>
+    </longDesc>
+    <property>
+      <name>prop2</name>
+      <className>boolean</className>
+      <desc>The prop2 property</desc>
+      <longDesc>
+<![CDATA[
+The prop2 property.
+<p>
+Some dummy prop2 documentation.
+]]>
+      </longDesc>
+    </property>
+  </component>
+  <converter>
+    <modelId>test</modelId>
+    <className>Converter1</className>
+    <sourceClassName>Converter1</sourceClassName>
+    <converterId>conv1</converterId>
+    <desc>The Converter1 converter</desc>
+    <longDesc>
+<![CDATA[
+The Converter1 converter.
+<p>
+This is a silly converter. It does nothing useful.
+]]>
+    </longDesc>
+  </converter>
+  <validator>
+    <modelId>test</modelId>
+    <className>Validator1</className>
+    <sourceClassName>Validator1</sourceClassName>
+    <validatorId>val1</validatorId>
+    <desc>The Validator1 validator</desc>
+    <longDesc>
+<![CDATA[
+The Validator1 validator.
+<p>
+This is a silly validator. It does nothing useful.
+]]>
+    </longDesc>
+  </validator>
+</model>
diff --git a/myfaces-builder-plugin/src/test/resources/builder/generation/goodfile-flat.xml b/myfaces-builder-plugin/src/test/resources/builder/generation/goodfile-flat.xml
new file mode 100644
index 0000000..2e69a70
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/generation/goodfile-flat.xml
@@ -0,0 +1,218 @@
+<?xml version='1.0' ?>
+
+<model>
+  <modelId>test</modelId>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.ComponentBase</className>
+    <sourceClassName>testpkg.ComponentBase</sourceClassName>
+    <type>base</type>
+    <family>base</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>A base component class</desc>
+    <longDesc>
+<![CDATA[
+A base component class.
+<p>
+This is a base component. It has no name, so is not a concrete component.
+]]>
+    </longDesc>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <generated>true</generated>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.ComponentInterface</className>
+    <sourceClassName>testpkg.ComponentInterface</sourceClassName>
+    <type>iface</type>
+    <family>iface</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>An interface that defines component properties</desc>
+    <longDesc>
+<![CDATA[
+An interface that defines component properties.
+<p>
+This is an interface component.
+]]>
+    </longDesc>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.SubclassComponent</className>
+    <parentClassName>testpkg.ComponentBase</parentClassName>
+    <sourceClassName>testpkg.ComponentGenSubclass</sourceClassName>
+    <sourceClassParentClassName>testpkg.ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="testpkg.ComponentInterface"/>
+    </interfaces>
+    <name>fooFromSubclass</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <generatedComponentClass>true</generatedComponentClass>
+    <desc>A class for which a concrete component will be created using "subclass mode" code-generation</desc>
+    <longDesc>A class for which a concrete component will be created using "subclass mode" code-generation.</longDesc>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+      <generated>true</generated>
+    </property>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.TemplateComponent</className>
+    <parentClassName>testpkg.ComponentBase</parentClassName>
+    <sourceClassName>testpkg.ComponentGenTemplate</sourceClassName>
+    <sourceClassParentClassName>testpkg.ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="testpkg.ComponentInterface"/>
+    </interfaces>
+    <name>fooFromTemplate</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <generatedComponentClass>true</generatedComponentClass>
+    <template>true</template>
+    <desc>A class for which a concrete component will be created using "template mode" code-generation</desc>
+    <longDesc>A class for which a concrete component will be created using "template mode" code-generation.</longDesc>
+    <property>
+      <name>prop2</name>
+      <className>boolean</className>
+      <desc>The prop2 property</desc>
+      <longDesc>
+<![CDATA[
+The prop2 property.
+<p>
+Some dummy prop2 documentation.
+]]>
+      </longDesc>
+    </property>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+      <generated>true</generated>
+    </property>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.ComponentManual</className>
+    <parentClassName>testpkg.ComponentBase</parentClassName>
+    <sourceClassName>testpkg.ComponentManual</sourceClassName>
+    <sourceClassParentClassName>testpkg.ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="testpkg.ComponentInterface"/>
+    </interfaces>
+    <name>foo</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <desc>A concrete component class that has been written by hand (no code generation)</desc>
+    <longDesc>A concrete component class that has been written by hand (no code generation).</longDesc>
+    <property>
+      <name>prop2</name>
+      <className>boolean</className>
+      <desc>The prop2 property</desc>
+      <longDesc>
+<![CDATA[
+The prop2 property.
+<p>
+Some dummy prop2 documentation.
+]]>
+      </longDesc>
+    </property>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+      <generated>true</generated>
+    </property>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+      <inherited>true</inherited>
+    </property>
+  </component>
+</model>
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/test/resources/builder/generation/goodfile.xml b/myfaces-builder-plugin/src/test/resources/builder/generation/goodfile.xml
new file mode 100644
index 0000000..d10451e
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/generation/goodfile.xml
@@ -0,0 +1,137 @@
+<?xml version='1.0' ?>
+
+<model>
+  <modelId>test</modelId>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.ComponentBase</className>
+    <sourceClassName>testpkg.ComponentBase</sourceClassName>
+    <type>base</type>
+    <family>base</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>A base component class</desc>
+    <longDesc>
+<![CDATA[
+A base component class.
+<p>
+This is a base component. It has no name, so is not a concrete component.
+]]>
+    </longDesc>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentation.
+]]>
+      </longDesc>
+      <generated>true</generated>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.ComponentInterface</className>
+    <sourceClassName>testpkg.ComponentInterface</sourceClassName>
+    <type>iface</type>
+    <family>iface</family>
+    <rendererType>BaseRenderer</rendererType>
+    <desc>An interface that defines component properties</desc>
+    <longDesc>
+<![CDATA[
+An interface that defines component properties.
+<p>
+This is an interface component.
+]]>
+    </longDesc>
+    <property>
+      <name>ifaceProp</name>
+      <className>java.lang.String</className>
+      <desc>The ifaceProp property</desc>
+      <longDesc>
+<![CDATA[
+The ifaceProp property.
+<p>
+Some dummy ifaceProp documentation.
+]]>
+      </longDesc>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.SubclassComponent</className>
+    <parentClassName>testpkg.ComponentBase</parentClassName>
+    <sourceClassName>testpkg.ComponentGenSubclass</sourceClassName>
+    <sourceClassParentClassName>testpkg.ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="testpkg.ComponentInterface"/>
+    </interfaces>
+    <name>fooFromSubclass</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <generatedComponentClass>true</generatedComponentClass>
+    <desc>A class for which a concrete component will be created using "subclass mode" code-generation</desc>
+    <longDesc>A class for which a concrete component will be created using "subclass mode" code-generation.</longDesc>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.TemplateComponent</className>
+    <parentClassName>testpkg.ComponentBase</parentClassName>
+    <sourceClassName>testpkg.ComponentGenTemplate</sourceClassName>
+    <sourceClassParentClassName>testpkg.ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="testpkg.ComponentInterface"/>
+    </interfaces>
+    <name>fooFromTemplate</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <generatedComponentClass>true</generatedComponentClass>
+    <template>true</template>
+    <desc>A class for which a concrete component will be created using "template mode" code-generation</desc>
+    <longDesc>A class for which a concrete component will be created using "template mode" code-generation.</longDesc>
+    <property>
+      <name>prop2</name>
+      <className>boolean</className>
+      <desc>The prop2 property</desc>
+      <longDesc>
+<![CDATA[
+The prop2 property.
+<p>
+Some dummy prop2 documentation.
+]]>
+      </longDesc>
+    </property>
+  </component>
+  <component>
+    <modelId>test</modelId>
+    <className>testpkg.ComponentManual</className>
+    <parentClassName>testpkg.ComponentBase</parentClassName>
+    <sourceClassName>testpkg.ComponentManual</sourceClassName>
+    <sourceClassParentClassName>testpkg.ComponentBase</sourceClassParentClassName>
+    <interfaces>
+      <interface name="testpkg.ComponentInterface"/>
+    </interfaces>
+    <name>foo</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <desc>A concrete component class that has been written by hand (no code generation)</desc>
+    <longDesc>A concrete component class that has been written by hand (no code generation).</longDesc>
+    <property>
+      <name>prop2</name>
+      <className>boolean</className>
+      <desc>The prop2 property</desc>
+      <longDesc>
+<![CDATA[
+The prop2 property.
+<p>
+Some dummy prop2 documentation.
+]]>
+      </longDesc>
+    </property>
+  </component>
+</model>
diff --git a/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentBase.java b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentBase.java
new file mode 100644
index 0000000..0d6af88
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentBase.java
@@ -0,0 +1,26 @@
+package testpkg;
+
+/**
+ * A base component class.
+ * <p>
+ * This is a base component. It has no name, so is not a concrete component.
+ * 
+ * @JSFComponent
+ *   type="base"
+ *   family="base"
+ *   defaultRendererType="BaseRenderer"
+ */
+
+public abstract class ComponentBase
+{
+    /**
+     * The prop1 property.
+     * <p>
+     * Some dummy prop1 documentation.
+     *
+     * @JSFProperty
+     */
+    public abstract String getProp1();
+    
+    public abstract void setProp1(String prop1);
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentGenSubclass.java b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentGenSubclass.java
new file mode 100644
index 0000000..d3328d2
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentGenSubclass.java
@@ -0,0 +1,15 @@
+package testpkg;
+
+/**
+ * A class for which a concrete component will be created using "subclass mode" code-generation.
+ * 
+ * @JSFComponent
+ *   name="fooFromSubclass"
+ *   type="foo"
+ *   family="foo"
+ *   defaultRendererType="FooRenderer"
+ *   class="testpkg.SubclassComponent"
+ */
+public abstract class ComponentGenSubclass extends ComponentBase implements ComponentInterface
+{
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentGenTemplate.java b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentGenTemplate.java
new file mode 100644
index 0000000..98d9a38
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentGenTemplate.java
@@ -0,0 +1,63 @@
+package testpkg;
+
+/**
+ * A class for which a concrete component will be created using "template mode" code-generation.
+ * 
+ * @JSFComponent
+ *   name="fooFromTemplate"
+ *   type="foo"
+ *   family="foo"
+ *   defaultRendererType="FooRenderer"
+ *   class="testpkg.TemplateComponent"
+ *   template="true"
+ */
+abstract class ComponentGenTemplate extends ComponentBase implements ComponentInterface
+{
+    String prop1;
+    boolean prop2;
+    
+    /**
+     * Implement the abstract property defined on the base class.
+     * Note that because this method is not annotated with the
+     * JSFProperty annotation, this comment does not become the
+     * documentation for the property itself.
+     */
+    public String getProp1()
+    {
+        return prop1;
+    }
+
+    public void setProp1(String prop1)
+    {
+        this.prop1 = prop1;
+    }
+
+    /**
+     * The prop2 property.
+     * <p>
+     * Some dummy prop2 documentation.
+     *
+     * @JSFProperty
+     */
+    public boolean getProp2() {
+        return prop2;
+    }
+    
+    public void setProp2(boolean prop2) {
+        this.prop2 = prop2;
+    }
+
+    /**
+     * Implement the method defined on ComponentInterface. Because this method does
+     * not use the JSFProperty annotation, the property settings are taken from the
+     * parent interface, not here.
+     */
+    public String getIfaceProp()
+    {
+        return null;
+    }
+
+    public void setIfaceProp(String val)
+    {
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentInterface.java b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentInterface.java
new file mode 100644
index 0000000..9b6c04d
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentInterface.java
@@ -0,0 +1,26 @@
+package testpkg;
+
+/**
+ * An interface that defines component properties.
+ * <p>
+ * This is an interface component.
+ * 
+ * @JSFComponent
+ *   type="iface"
+ *   family="iface"
+ *   defaultRendererType="BaseRenderer"
+ */
+
+public interface ComponentInterface
+{
+    /**
+     * The ifaceProp property.
+     * <p>
+     * Some dummy ifaceProp documentation.
+     *
+     * @JSFProperty
+     */
+    String getIfaceProp();
+    
+    void setIfaceProp(String val);
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentManual.java b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentManual.java
new file mode 100644
index 0000000..2e1f305
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/generation/testpkg/ComponentManual.java
@@ -0,0 +1,61 @@
+package testpkg;
+
+/**
+ * A concrete component class that has been written by hand (no code generation).
+ * 
+ * @JSFComponent
+ *   name="foo"
+ *   type="foo"
+ *   family="foo"
+ *   defaultRendererType="FooRenderer"
+ */
+public class ComponentManual extends ComponentBase implements ComponentInterface
+{
+    String prop1;
+    boolean prop2;
+    
+    /**
+     * Implement the abstract property defined on the base class.
+     * Note that because this method is not annotated with the
+     * JSFProperty annotation, this comment does not become the
+     * documentation for the property itself.
+     */
+    public String getProp1()
+    {
+        return prop1;
+    }
+
+    public void setProp1(String prop1)
+    {
+        this.prop1 = prop1;
+    }
+
+    /**
+     * The prop2 property.
+     * <p>
+     * Some dummy prop2 documentation.
+     *
+     * @JSFProperty
+     */
+    public boolean getProp2() {
+        return prop2;
+    }
+    
+    public void setProp2(boolean prop2) {
+        this.prop2 = prop2;
+    }
+
+    /**
+     * Implement the method defined on ComponentInterface. Because this method does
+     * not use the JSFProperty annotation, the property settings are taken from the
+     * parent interface, not here.
+     */
+    public String getIfaceProp()
+    {
+        return null;
+    }
+
+    public void setIfaceProp(String val)
+    {
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/simple/Foo.java b/myfaces-builder-plugin/src/test/resources/builder/simple/Foo.java
new file mode 100644
index 0000000..950adb1
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/simple/Foo.java
@@ -0,0 +1,30 @@
+/**
+ * The Foo component.
+ * <p>
+ * This is a foo component. It does nothing useful.
+ * 
+ * @JSFComponent
+ *   name="foo"
+ *   type="foo"
+ *   family="foo"
+ *   defaultRendererType="FooRenderer"
+ */
+public class Foo
+{
+    String prop1;
+    
+    /**
+     * The prop1 property.
+     * <p>
+     * Some dummy prop1 documentatoin.
+     *
+     * @JSFProperty
+     */
+    public String getProp1() {
+        return prop1;
+    }
+    
+    public void setProp1(String prop1) {
+        this.prop1 = prop1;
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/simple/goodfile.xml b/myfaces-builder-plugin/src/test/resources/builder/simple/goodfile.xml
new file mode 100644
index 0000000..f3ca12f
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/simple/goodfile.xml
@@ -0,0 +1,34 @@
+<?xml version='1.0' ?>
+
+<model>
+  <modelId>test</modelId>
+  <component>
+    <modelId>test</modelId>
+    <className>Foo</className>
+    <sourceClassName>Foo</sourceClassName>
+    <name>foo</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <desc>The Foo component</desc>
+    <longDesc>
+<![CDATA[
+The Foo component.
+<p>
+This is a foo component. It does nothing useful.
+]]>
+    </longDesc>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentatoin.
+]]>
+      </longDesc>
+    </property>
+  </component>
+</model>
diff --git a/myfaces-builder-plugin/src/test/resources/builder/simple15/Foo.java b/myfaces-builder-plugin/src/test/resources/builder/simple15/Foo.java
new file mode 100644
index 0000000..fe1d318
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/simple15/Foo.java
@@ -0,0 +1,26 @@
+import org.apache.myfaces.buildtools.annotation.*;
+
+/**
+ * The Foo component defined via java15 annotations.
+ * <p>
+ * This is an annotated foo component. It does nothing useful.
+ */
+@JSFComponent(name="foo", type="foo", family="foo", defaultRendererType="FooRenderer")
+public class Foo
+{
+    String prop1;
+    
+    /**
+     * The prop1 property.
+     * <p>
+     * Some dummy prop1 documentatoin.
+     */
+    @JSFProperty
+    public String getProp1() {
+        return prop1;
+    }
+    
+    public void setProp1(String prop1) {
+        this.prop1 = prop1;
+    }
+}
diff --git a/myfaces-builder-plugin/src/test/resources/builder/simple15/goodfile.xml b/myfaces-builder-plugin/src/test/resources/builder/simple15/goodfile.xml
new file mode 100644
index 0000000..3cb04e0
--- /dev/null
+++ b/myfaces-builder-plugin/src/test/resources/builder/simple15/goodfile.xml
@@ -0,0 +1,34 @@
+<?xml version='1.0' ?>
+
+<model>
+  <modelId>test</modelId>
+  <component>
+    <modelId>test</modelId>
+    <className>Foo</className>
+    <sourceClassName>Foo</sourceClassName>
+    <name>foo</name>
+    <type>foo</type>
+    <family>foo</family>
+    <rendererType>FooRenderer</rendererType>
+    <desc>The Foo component defined via java15 annotations</desc>
+    <longDesc>
+<![CDATA[
+The Foo component defined via java15 annotations.
+<p>
+This is an annotated foo component. It does nothing useful.
+]]>
+    </longDesc>
+    <property>
+      <name>prop1</name>
+      <className>java.lang.String</className>
+      <desc>The prop1 property</desc>
+      <longDesc>
+<![CDATA[
+The prop1 property.
+<p>
+Some dummy prop1 documentatoin.
+]]>
+      </longDesc>
+    </property>
+  </component>
+</model>