[maven-release-plugin] copy for tag lu4242_m2_plugins_103_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..9cc8e65
--- /dev/null
+++ b/myfaces-builder-plugin/pom.xml
@@ -0,0 +1,182 @@
+<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.3</version>
+ </parent>
+
+ <groupId>org.apache.myfaces.buildtools</groupId>
+ <artifactId>myfaces-builder-plugin</artifactId>
+ <version>1.0.3</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>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ </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.9.1</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_103_release/myfaces-builder-plugin</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/myfaces/myfaces-build-tools/branches/lu4242_m2_plugins_103_release/myfaces-builder-plugin</developerConnection>
+ <url>http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/tags/lu4242_m2_plugins_103_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..9903a8b
--- /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 myfaces-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..972894a
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/Flattener.java
@@ -0,0 +1,290 @@
+/*
+ * 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.Collection;
+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.AttributeMeta;
+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.PropertyMeta;
+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.model.MethodSignatureMeta;
+
+/**
+ */
+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();
+ flattenTagAttributes();
+ }
+
+ 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);
+ }
+
+ private void flattenTagAttributes()
+ {
+ List tags = model.getTags();
+ for (Iterator i = tags.iterator(); i.hasNext();)
+ {
+ TagMeta val = (TagMeta) i.next();
+ flattenTag(val);
+ }
+ }
+
+ /**
+ * This method allows component tag classes to be
+ * used with tags, so it is possible to inherit attribute
+ * for component tags. But tags cannot inherit
+ * attributes from other tags.
+ *
+ */
+ private void flattenTag(TagMeta tag)
+ {
+ if (flattened.contains(tag))
+ {
+ // already done
+ return;
+ }
+
+ if (tag.getSourceClassParentClassName() == null)
+ {
+ //No need to scan
+ return;
+ }
+ ComponentMeta component = model.findComponentByTagClassName(
+ tag.getSourceClassParentClassName());
+
+ if (null != component)
+ {
+ Collection propertyList = component.getPropertyList();
+ for (Iterator it = propertyList.iterator(); it.hasNext();)
+ {
+ PropertyMeta property = (PropertyMeta) it.next();
+
+ //Just add all non tag excluded properties.
+ if (!property.isTagExcluded().booleanValue())
+ {
+ AttributeMeta attribute = new AttributeMeta();
+ if (property.isMethodExpression())
+ {
+ attribute.setClassName("javax.el.MethodExpression");
+ MethodSignatureMeta sig = property.getMethodBindingSignature();
+ attribute.setDeferredMethodSignature(
+ sig.getReturnType()+" myMethod("+sig.getParameterTypesAsString()+")");
+ }
+ else if (null == property.isRtexprvalue() || !property.isRtexprvalue().booleanValue())
+ {
+ attribute.setDeferredValueType(property.getClassName());
+ attribute.setClassName("javax.el.ValueExpression");
+ }
+ else
+ {
+ //rtexprvalue = true, set className as expected
+ attribute.setClassName(property.getClassName());
+ }
+ attribute.setRtexprvalue(property.isRtexprvalue());
+
+ attribute.setDescription(property.getDescription());
+ attribute.setLongDescription(property.getLongDescription());
+ attribute.setName(property.getJspName());
+ attribute.setRequired(property.isRequired());
+
+ //just add attribute to tag
+ AttributeMeta attributeInTag = tag.getAttribute(attribute.getName());
+
+ if (attributeInTag != null)
+ {
+ //attributeInTag takes precedence, so
+ //we have to merge and copy
+ attribute.merge(attributeInTag);
+ attributeInTag.copy(attribute);
+ }
+ else
+ {
+ //Add it to tag
+ tag.addAttribute(attribute);
+ }
+ }
+ }
+ }
+
+ flattened.add(tag);
+ }
+}
\ 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..af4a142
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeComponentsMojo.java
@@ -0,0 +1,691 @@
+/*
+ * 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;
+
+/**
+ * Maven goal to generate java source code for Component classes.
+ *
+ * <p>It uses velocity to generate templates, and has the option to define custom templates.</p>
+ * <p>The executed template has the following variables available to it:</p>
+ * <ul>
+ * <li>utils : Returns an instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils,
+ * it contains some useful methods.</li>
+ * <li>component : Returns the current instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta</li>
+ * <li>innersource : code to be injected from the template class when template
+ * mode is used</li>
+ * </ul>
+ *
+ * @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;
+
+ /**
+ * Defines the directory where the metadata file (META-INF/myfaces-metadata.xml) is loaded.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Injected name of file generated by earlier run of BuildMetaDataMojo goal.
+ *
+ * @parameter
+ */
+ private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+ /**
+ * The directory used to load templates into velocity environment.
+ *
+ * @parameter expression="src/main/resources/META-INF"
+ */
+ private File templateSourceDirectory;
+
+ /**
+ * The directory where all generated files are created. This directory is added as a
+ * compile source root automatically like src/main/java is.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+ */
+ private File generatedSourceDirectory;
+
+ /**
+ * Generate only component classes that starts with the specified package prefix.
+ *
+ * @parameter
+ */
+ private String packageContains;
+
+ /**
+ * Generate only component classes that starts with the specified component type prefix.
+ *
+ * @parameter
+ */
+ private String typePrefix;
+
+ /**
+ * Log and continue execution when generating component classes.
+ * <p>
+ * If this property is set to false (default), errors when a component class is generated stops
+ * execution immediately.
+ * </p>
+ *
+ * @parameter
+ */
+ private boolean force;
+
+ /**
+ * Defines the jsf version (1.1 or 1.2), used to take the default templates for each version.
+ * <p>
+ * If version is 1.1, the default templateComponentName is 'componentClass11.vm' and if version
+ * is 1.2 the default templateComponentName is 'componentClass12.vm'.
+ * </p>
+ *
+ * @parameter
+ */
+ private String jsfVersion;
+
+ /**
+ * Define the models that should be included when generate component classes. If not set, the
+ * current model identified by the artifactId is used.
+ * <p>
+ * Each model built by build-metadata goal has a modelId, that by default is the artifactId of
+ * the project. Setting this property defines which objects tied in a specified modelId should
+ * be taken into account.
+ * </p>
+ * <p>In this case, limit component generation only to the components defined in the models
+ * identified by the modelId defined. </p>
+ * <p>This is useful when you need to generate files that take information defined on other
+ * projects</p>
+ * <p>Example:</p>
+ * <pre>
+ * <modelIds>
+ * <modelId>model1</modelId>
+ * <modelId>model2</modelId>
+ * </modelIds>
+ * </pre>
+ *
+ * @parameter
+ */
+ private List modelIds;
+
+ /**
+ * The name of the template used to generate component classes. According to the value on
+ * jsfVersion property the default if this property is not set could be componentClass11.vm (1.1) or
+ * componentClass12.vm (1.2)
+ *
+ * @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());
+
+ try
+ {
+ _generateComponent(velocityEngine, builder,component,baseContext);
+ }
+ catch(MojoExecutionException e)
+ {
+ if (force)
+ {
+ log.severe(e.getMessage());
+ }
+ else
+ {
+ //Stop execution throwing exception
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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);
+
+ writer.append(" ");
+ writer.append(declaration);
+ String sourceCode = method.getSourceCode();
+ if(sourceCode != null && sourceCode.length() > 0)
+ {
+ writer.append('\n');
+ writer.append(" ");
+ writer.append('{');
+ writer.append(method.getSourceCode());
+ writer.append('}');
+ writer.append('\n');
+ writer.append('\n');
+ }
+ else
+ {
+ writer.append(';');
+ 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..669a26a
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConfigMojo.java
@@ -0,0 +1,365 @@
+/*
+ * 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;
+
+ /**
+ * Defines the directory where the metadata file (META-INF/myfaces-metadata.xml) is loaded,
+ * and the generated file named by xmlFile parameter is created.
+ *
+ * @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..c26fd93
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeConverterTagsMojo.java
@@ -0,0 +1,446 @@
+/*
+ * 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.
+ *
+ * <p>It uses velocity to generate templates, and has the option to define custom templates.</p>
+ * <p>The executed template has the following variables available to it:</p>
+ * <ul>
+ * <li>utils : Returns an instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils,
+ * it contains some useful methods.</li>
+ * <li>converter : Returns the current instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta</li>
+ * </ul>
+ *
+ * @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;
+
+ /**
+ * Defines the directory where the metadata file (META-INF/myfaces-metadata.xml) is loaded.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Injected name of file generated by earlier run of BuildMetaDataMojo goal.
+ *
+ * @parameter
+ */
+ private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+ /**
+ * The directory used to load templates into velocity environment.
+ *
+ * @parameter expression="src/main/resources/META-INF"
+ */
+ private File templateSourceDirectory;
+
+ /**
+ * 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;
+
+ /**
+ * The name of the template used to generate converter tag classes. According to the value on
+ * jsfVersion property the default if this property is not set could be tagConverterClass11.vm (1.1) or
+ * tagConverterClass12.vm (1.2)
+ *
+ * @parameter
+ */
+ private String templateTagName;
+
+ /**
+ * The directory where all generated files are created. This directory is added as a
+ * compile source root automatically like src/main/java is.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+ * @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;
+
+ /**
+ * Log and continue execution when generating converter tag classes.
+ * <p>
+ * If this property is set to false (default), errors when a converter tag class is generated stops
+ * execution immediately.
+ * </p>
+ *
+ * @parameter
+ */
+ private boolean force;
+
+ /**
+ * Defines the jsf version (1.1 or 1.2), used to take the default templates for each version.
+ * <p>
+ * If version is 1.1, the default templateTagName is 'tagConverterClass11.vm' and if version
+ * is 1.2 the default templateTagName is 'tagConverterClass12.vm'.
+ * </p>
+ *
+ * @parameter
+ */
+ private String jsfVersion;
+
+ /**
+ * Define the models that should be included when generate converter tag classes. If not set, the
+ * current model identified by the artifactId is used.
+ * <p>
+ * Each model built by build-metadata goal has a modelId, that by default is the artifactId of
+ * the project. Setting this property defines which objects tied in a specified modelId should
+ * be taken into account.
+ * </p>
+ * <p>In this case, limit converter tag generation only to the components defined in the models
+ * identified by the modelId defined. </p>
+ * <p>This is useful when you need to generate files that take information defined on other
+ * projects.</p>
+ * <p>Example:</p>
+ * <pre>
+ * <modelIds>
+ * <modelId>model1</modelId>
+ * <modelId>model2</modelId>
+ * </modelIds>
+ * </pre>
+ *
+ * @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());
+ try
+ {
+ _generateConverter(velocityEngine, converter,baseContext);
+ }
+ catch(MojoExecutionException e)
+ {
+ if (force)
+ {
+ log.severe(e.getMessage());
+ }
+ else
+ {
+ //Stop execution throwing exception
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ //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..f55ff39
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeTagsMojo.java
@@ -0,0 +1,446 @@
+/*
+ * 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.
+ *
+ * <p>It uses velocity to generate templates, and has the option to define custom templates.</p>
+ * <p>The executed template has the following variables available to it:</p>
+ * <ul>
+ * <li>utils : Returns an instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils,
+ * it contains some useful methods.</li>
+ * <li>component : Returns the current instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta</li>
+ * </ul>
+ *
+ * @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;
+
+ /**
+ * Defines the directory where the metadata file (META-INF/myfaces-metadata.xml) is loaded.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Injected name of file generated by earlier run of BuildMetaDataMojo goal.
+ *
+ * @parameter
+ */
+ private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+ /**
+ * The directory used to load templates into velocity environment.
+ *
+ * @parameter expression="src/main/resources/META-INF"
+ */
+ private File templateSourceDirectory;
+
+ /**
+ * 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;
+
+ /**
+ * The name of the template used to generate component tag classes. According to the value on
+ * jsfVersion property the default if this property is not set could be tagClass11.vm (1.1) or
+ * tagClass12.vm (1.2)
+ *
+ * @parameter
+ */
+ private String templateTagName;
+
+ /**
+ * The directory where all generated files are created. This directory is added as a
+ * compile source root automatically like src/main/java is.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+ * @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;
+
+ /**
+ * Log and continue execution when generating component tag classes.
+ * <p>
+ * If this property is set to false (default), errors when a component tag class is generated stops
+ * execution immediately.
+ * </p>
+ *
+ * @parameter
+ */
+ private boolean force;
+
+ /**
+ * Defines the jsf version (1.1 or 1.2), used to take the default templates for each version.
+ * <p>
+ * If version is 1.1, the default templateTagName is 'tagClass11.vm' and if version
+ * is 1.2 the default templateTagName is 'tagClass12.vm'.
+ * </p>
+ *
+ * @parameter
+ */
+ private String jsfVersion;
+
+ /**
+ * Define the models that should be included when generate component tag classes. If not set, the
+ * current model identified by the artifactId is used.
+ * <p>
+ * Each model built by build-metadata goal has a modelId, that by default is the artifactId of
+ * the project. Setting this property defines which objects tied in a specified modelId should
+ * be taken into account.
+ * </p>
+ * <p>In this case, limit component tag generation only to the components defined in the models
+ * identified by the modelId defined. </p>
+ * <p>This is useful when you need to generate files that take information defined on other
+ * projects.</p>
+ * <p>Example:</p>
+ * <pre>
+ * <modelIds>
+ * <modelId>model1</modelId>
+ * <modelId>model2</modelId>
+ * </modelIds>
+ * </pre>
+ *
+ * @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());
+ try
+ {
+ _generateComponent(velocityEngine, component,baseContext);
+ }
+ catch(MojoExecutionException e)
+ {
+ if (force)
+ {
+ log.severe(e.getMessage());
+ }
+ else
+ {
+ //Stop execution throwing exception
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ //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..8bb761f
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorTagsMojo.java
@@ -0,0 +1,446 @@
+/*
+ * 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.
+ *
+ * <p>It uses velocity to generate templates, and has the option to define custom templates.</p>
+ * <p>The executed template has the following variables available to it:</p>
+ * <ul>
+ * <li>utils : Returns an instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils,
+ * it contains some useful methods.</li>
+ * <li>validator : Returns the current instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta</li>
+ * </ul>
+ *
+ * @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;
+
+ /**
+ * Defines the directory where the metadata file (META-INF/myfaces-metadata.xml) is loaded.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Injected name of file generated by earlier run of BuildMetaDataMojo goal.
+ *
+ * @parameter
+ */
+ private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+ /**
+ * The directory used to load templates into velocity environment.
+ *
+ * @parameter expression="src/main/resources/META-INF"
+ */
+ private File templateSourceDirectory;
+
+ /**
+ * 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;
+
+ /**
+ * The name of the template used to generate validator tag classes. According to the value on
+ * jsfVersion property the default if this property is not set could be tagValidatorClass11.vm (1.1) or
+ * tagValidatorClass12.vm (1.2)
+ *
+ * @parameter
+ */
+ private String templateTagName;
+
+ /**
+ * The directory where all generated files are created. This directory is added as a
+ * compile source root automatically like src/main/java is.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+ * @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;
+
+ /**
+ * Log and continue execution when generating validator tag classes.
+ * <p>
+ * If this property is set to false (default), errors when a validator tag class is generated stops
+ * execution immediately.
+ * </p>
+ *
+ * @parameter
+ */
+ private boolean force;
+
+ /**
+ * Defines the jsf version (1.1 or 1.2), used to take the default templates for each version.
+ * <p>
+ * If version is 1.1, the default templateTagName is 'tagValidatorClass11.vm' and if version
+ * is 1.2 the default templateTagName is 'tagValidatorClass12.vm'.
+ * </p>
+ *
+ * @parameter
+ */
+ private String jsfVersion;
+
+ /**
+ * Define the models that should be included when generate validator tag classes. If not set, the
+ * current model identified by the artifactId is used.
+ * <p>
+ * Each model built by build-metadata goal has a modelId, that by default is the artifactId of
+ * the project. Setting this property defines which objects tied in a specified modelId should
+ * be taken into account.
+ * </p>
+ * <p>In this case, limit converter tag generation only to the components defined in the models
+ * identified by the modelId defined. </p>
+ * <p>This is useful when you need to generate files that take information defined on other
+ * projects.</p>
+ * <p>Example:</p>
+ * <pre>
+ * <modelIds>
+ * <modelId>model1</modelId>
+ * <modelId>model2</modelId>
+ * </modelIds>
+ * </pre>
+ *
+ * @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());
+ try
+ {
+ _generateValidator(velocityEngine, validator,baseContext);
+ }
+ catch(MojoExecutionException e)
+ {
+ if (force)
+ {
+ log.severe(e.getMessage());
+ }
+ else
+ {
+ //Stop execution throwing exception
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ //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..ab12725
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/MakeValidatorsMojo.java
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ *
+ * <p>It uses velocity to generate templates, and has the option to define custom templates.</p>
+ * <p>The executed template has the following variables available to it:</p>
+ * <ul>
+ * <li>utils : Returns an instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.utils.MyfacesUtils,
+ * it contains some useful methods.</li>
+ * <li>validator : Returns the current instance of
+ * org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta</li>
+ * </ul>
+ *
+ * @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;
+
+ /**
+ * Defines the directory where the metadata file (META-INF/myfaces-metadata.xml) is loaded.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Injected name of file generated by earlier run of BuildMetaDataMojo goal.
+ *
+ * @parameter
+ */
+ private String metadataFile = "META-INF/myfaces-metadata.xml";
+
+ /**
+ * The directory used to load templates into velocity environment.
+ *
+ * @parameter expression="src/main/resources/META-INF"
+ */
+ private File templateSourceDirectory;
+
+ /**
+ * The directory where all generated files are created. This directory is added as a
+ * compile source root automatically like src/main/java is.
+ *
+ * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/java"
+ */
+ private File generatedSourceDirectory;
+
+ /**
+ * Only generate tag classes that contains that package prefix
+ *
+ * @parameter
+ */
+ private String packageContains;
+
+ /**
+ * Log and continue execution when generating validator classes.
+ * <p>
+ * If this property is set to false (default), errors when a validator class is generated stops
+ * execution immediately.
+ * </p>
+ *
+ * @parameter
+ */
+ private boolean force;
+
+ /**
+ * Defines the jsf version (1.1 or 1.2), used to take the default templates for each version.
+ * <p>
+ * If version is 1.1, the default templateValidatorName is 'validatorClass11.vm' and if version
+ * is 1.2 the default templateValidatorName is 'validatorClass12.vm'.
+ * </p>
+ *
+ * @parameter
+ */
+ private String jsfVersion;
+
+ /**
+ * Define the models that should be included when generate validator classes. If not set, the
+ * current model identified by the artifactId is used.
+ * <p>
+ * Each model built by build-metadata goal has a modelId, that by default is the artifactId of
+ * the project. Setting this property defines which objects tied in a specified modelId should
+ * be taken into account.
+ * </p>
+ * <p>In this case, limit converter tag generation only to the components defined in the models
+ * identified by the modelId defined. </p>
+ * <p>This is useful when you need to generate files that take information defined on other
+ * projects.</p>
+ * <p>Example:</p>
+ * <pre>
+ * <modelIds>
+ * <modelId>model1</modelId>
+ * <modelId>model2</modelId>
+ * </modelIds>
+ * </pre>
+ *
+ * @parameter
+ */
+ private List modelIds;
+
+ /**
+ * The name of the template used to generate validator classes. According to the value on
+ * jsfVersion property the default if this property is not set could be validatorClass11.vm (1.1) or
+ * validatorClass12.vm (1.2)
+ *
+ * @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());
+ try
+ {
+ _generateValidator(velocityEngine, builder,validator,baseContext);
+ }
+ catch(MojoExecutionException e)
+ {
+ if (force)
+ {
+ log.severe(e.getMessage());
+ }
+ else
+ {
+ //Stop execution throwing exception
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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..e39a527
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/AttributeMeta.java
@@ -0,0 +1,256 @@
+/*
+ * 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;
+ private String _deferredValueType;
+ private String _deferredMethodSignature;
+ private Boolean _exclude;
+
+ 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.writeElement("deferredValueType", am._deferredValueType);
+ out.writeElement("deferredMethodSignature", am._deferredMethodSignature);
+ out.writeElement("exclude", am._exclude);
+ 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");
+ digester.addBeanPropertySetter(newPrefix + "/deferredValueType");
+ digester.addBeanPropertySetter(newPrefix + "/deferredMethodSignature");
+ digester.addBeanPropertySetter(newPrefix + "/exclude");
+ }
+
+ /**
+ * 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);
+ _deferredValueType = ModelUtils.merge(this._deferredValueType, other._deferredValueType);
+ _deferredMethodSignature = ModelUtils.merge(this._deferredMethodSignature, other._deferredMethodSignature);
+ _exclude = ModelUtils.merge(this._exclude, other._exclude);
+ }
+
+ /**
+ * Copy all attributes in other to this instance.
+ *
+ * @since 1.0.3
+ * @param other
+ */
+ public void copy(AttributeMeta other)
+ {
+ _name = other._name;
+ _required = other._required;
+ _rtexprvalue = other._rtexprvalue;
+ _description = other._description;
+ _longDescription = other._longDescription;
+ _deferredValueType = other._deferredValueType;
+ _deferredMethodSignature = other._deferredMethodSignature;
+ _exclude = other._exclude;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * @since 1.0.3
+ */
+ public void setDeferredValueType(String deferredValueType)
+ {
+ _deferredValueType = deferredValueType;
+ }
+
+ /**
+ * Indicate the type that values should be
+ * cast on tld. It is supposed that the className is
+ * javax.el.ValueExpression to apply it.
+ *
+ * @since 1.0.3
+ */
+ public String getDeferredValueType()
+ {
+ return _deferredValueType;
+ }
+
+ /**
+ * @since 1.0.3
+ */
+ public void setDeferredMethodSignature(String deferredMethodSignature)
+ {
+ _deferredMethodSignature = deferredMethodSignature;
+ }
+
+ /**
+ * Indicate the method signature that values should be
+ * cast on tld. It is supposed that the className is
+ * javax.el.MethodExpression to apply it.
+ *
+ * @since 1.0.3
+ */
+ public String getDeferredMethodSignature()
+ {
+ return _deferredMethodSignature;
+ }
+
+ /**
+ * @since 1.0.3
+ */
+ public Boolean isExclude()
+ {
+ return ModelUtils.defaultOf(_exclude, false);
+ }
+
+ /**
+ * @since 1.0.3
+ */
+ public void setExclude(Boolean exclude)
+ {
+ _exclude = exclude;
+ }
+}
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..cb0bccd
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/ConverterMeta.java
@@ -0,0 +1,295 @@
+/*
+ * 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)
+ {
+ //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..0c92728
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/Model.java
@@ -0,0 +1,357 @@
+/*
+ * 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 Map _componentsByTagClass = 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);
+ if (null != component.getTagClass())
+ {
+ _componentsByTagClass.put(component.getTagClass(), 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);
+ }
+
+ public ComponentMeta findComponentByTagClassName(String className)
+ {
+ return (ComponentMeta) _componentsByTagClass.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..febc4f9
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/model/PropertyMeta.java
@@ -0,0 +1,550 @@
+/*
+ * 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;
+
+ private String _deferredValueType;
+
+ 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;
+ _deferredValueType = pm._deferredValueType;
+ }
+
+ /**
+ * 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.writeElement("deferredValueType", pm._deferredValueType);
+ 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");
+ digester.addBeanPropertySetter(newPrefix + "/deferredValueType", "deferredValueType");
+ 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);
+ _deferredValueType = ModelUtils.merge(this._deferredValueType, other._deferredValueType);
+ }
+
+ /**
+ * 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()));
+ }
+
+ /**
+ * @since 1.0.3
+ */
+ public void setDeferredValueType(String deferredValueType)
+ {
+ _deferredValueType = deferredValueType;
+ }
+
+ /**
+ * Indicate the type that values should be
+ * cast on tld. It is supposed that the className is
+ * javax.el.ValueExpression to apply it.
+ *
+ * @since 1.0.3
+ */
+ public String getDeferredValueType()
+ {
+ return _deferredValueType;
+ }
+}
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..5388a64
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/qdox/QdoxModelBuilder.java
@@ -0,0 +1,1759 @@
+/*
+ * 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.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+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;
+
+/**
+ * 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");
+ }
+ //System.out.println("includes:"+includes+" excludes:"+excludes);
+
+ 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)
+ {
+ addFileToJavaDocBuilder(builder,selector, path, path.getPath());
+ }
+
+
+ private void addFileToJavaDocBuilder(JavaDocBuilder builder,
+ FileSelector selector, File path, String basePath)
+ {
+ 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], basePath);
+ }
+ }
+ else
+ {
+ File file = path;
+
+ try
+ {
+ String name = file.getPath();
+ while (name.startsWith("/"))
+ {
+ name = name.substring(1);
+ }
+ while (name.startsWith("\\"))
+ {
+ name = name.substring(1);
+ }
+ SourceFileInfo fileInfo = new SourceFileInfo(file,name);
+ if (selector.isSelected(fileInfo))
+ {
+ //System.out.println("file:"+name);
+ 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;
+ }
+ initConverterAncestry(processedClasses, model, converter);
+ // TODO: why is there no check for Converter class existence here??
+ // ANS: there is no automatic generation of converter class.
+
+ // Check if the 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, (AbstractJavaEntity)tag.getContext(), clazz, model);
+ }
+ anno = getAnnotation(clazz, DOC_CONVERTER);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processConverter(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
+ }
+
+ // validators
+ tag = clazz.getTagByName(DOC_VALIDATOR, false);
+ if (tag != null)
+ {
+ Map props = tag.getNamedParameterMap();
+ processValidator(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
+ }
+ anno = getAnnotation(clazz, DOC_VALIDATOR);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processValidator(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
+ }
+
+ // components
+ tag = clazz.getTagByName(DOC_COMPONENT, false);
+ if (tag != null)
+ {
+ Map props = tag.getNamedParameterMap();
+ processComponent(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
+ }
+ anno = getAnnotation(clazz, DOC_COMPONENT);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processComponent(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
+ }
+
+ //tag
+ tag = clazz.getTagByName(DOC_TAG, false);
+ if (tag != null)
+ {
+ Map props = tag.getNamedParameterMap();
+ processTag(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
+ }
+ anno = getAnnotation(clazz, DOC_TAG);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processTag(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
+ }
+
+ // renderKit
+ tag = clazz.getTagByName(DOC_RENDERKIT, false);
+ if (tag != null)
+ {
+ Map props = tag.getNamedParameterMap();
+ processRenderKit(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
+ }
+ anno = getAnnotation(clazz, DOC_RENDERKIT);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processRenderKit(props, (AbstractJavaEntity)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, (AbstractJavaEntity)tag.getContext(), clazz, model);
+ }
+ }
+
+ anno = getAnnotation(clazz, DOC_RENDERER);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processRenderer(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
+ }
+
+ anno = getAnnotation(clazz, DOC_RENDERERS);
+ if (anno != null)
+ {
+ Object jspProps = anno.getNamedParameter("renderers");
+
+ if (jspProps instanceof Annotation)
+ {
+ Annotation jspPropertiesAnno = (Annotation) jspProps;
+ Map props = jspPropertiesAnno.getNamedParameterMap();
+ processRenderer(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
+ }
+ else
+ {
+ List jspPropsList = (List) jspProps;
+ for (int i = 0; i < jspPropsList.size();i++)
+ {
+ Annotation ranno = (Annotation) jspPropsList.get(i);
+
+ Map props = ranno.getNamedParameterMap();
+ processRenderer(props, (AbstractJavaEntity)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;
+ }
+
+
+ private String getFullyQualifiedClassName(JavaClass clazz, String fqn)
+ {
+ //QDox 1.9 bug. getFullyQualifiedName does not resolve
+ //correctly classes like javax.servlet.jsp.tagext.TagSupport as parent
+ //of a class with @JSFJspTag. The temporal solution is scan
+ //the imports, looking for this type and if it is found replace it.
+ //Fixed on 1.9.1, but better let the code as is
+ /*
+ if (fqn.indexOf('.') == -1)
+ {
+ String [] imports = clazz.getSource().getImports();
+ for (int i = 0; i < imports.length; i++)
+ {
+ if (imports[i].endsWith(fqn))
+ {
+ fqn = imports[i];
+ }
+ }
+ }*/
+ return fqn;
+ }
+
+ /**
+ * 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"))
+ {
+ fqn = getFullyQualifiedClassName(clazz,fqn);
+ 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)
+ {
+ String parentClazzName = parentClazz.getFullyQualifiedName();
+
+ parentClazzName = getFullyQualifiedClassName(clazz,parentClazzName);
+
+ ComponentMeta parentComponent = model
+ .findComponentByClassName(parentClazzName);
+ 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)
+ {
+ String parentClazzName = parentClazz.getFullyQualifiedName();
+
+ parentClazzName = getFullyQualifiedClassName(clazz,parentClazzName);
+
+ ValidatorMeta parentComponent = model
+ .findValidatorByClassName(parentClazzName);
+ if (parentComponent != null)
+ {
+ modelItem.setParentClassName(parentComponent.getClassName());
+ break;
+ }
+ parentClazz = parentClazz.getSuperJavaClass();
+ }
+ }
+
+ /**
+ * Same as initComponentAncestry but for converters
+ */
+ private void initConverterAncestry(Map javaClassByName, Model model, ClassMeta modelItem)
+ {
+ JavaClass clazz = (JavaClass) javaClassByName.get(modelItem.getSourceClassName());
+ JavaClass parentClazz = clazz.getSuperJavaClass();
+ while (parentClazz != null)
+ {
+ String parentClazzName = parentClazz.getFullyQualifiedName();
+
+ parentClazzName = getFullyQualifiedClassName(clazz,parentClazzName);
+
+ ConverterMeta parentComponent = model
+ .findConverterByClassName(parentClazzName);
+ 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, (AbstractJavaEntity)tag.getContext(), clazz,
+ method, ctag);
+ }
+
+ Annotation anno = getAnnotation(method, DOC_JSP_ATTRIBUTE);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processTagAttribute(props, (AbstractJavaEntity)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, (AbstractJavaEntity)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 fullyQualifiedReturnType = returnType.getJavaClass().getFullyQualifiedName();
+
+ fullyQualifiedReturnType = getFullyQualifiedClassName(clazz,fullyQualifiedReturnType);
+
+ if (returnType.isArray() && (fullyQualifiedReturnType.indexOf('[') == -1))
+ {
+ for (int i = 0; i < returnType.getDimensions();i++)
+ {
+ fullyQualifiedReturnType = fullyQualifiedReturnType + "[]";
+ }
+ }
+
+ String className = getString(clazz,"className",props, fullyQualifiedReturnType);
+ String deferredValueType = getString(clazz, "deferredValueType", props, null);
+ String deferredMethodSignature = getString(clazz, "deferredMethodSignature", props, null);
+ Boolean exclude = getBoolean(clazz, "exclude", props, null);
+
+ AttributeMeta a = new AttributeMeta();
+ a.setName(methodToPropName(method.getName()));
+ a.setClassName(className);
+ a.setRequired(required);
+ a.setRtexprvalue(rtexprvalue);
+ a.setDescription(shortDescription);
+ a.setLongDescription(longDescription);
+ a.setDeferredValueType(deferredValueType);
+ a.setDeferredMethodSignature(deferredMethodSignature);
+ a.setExclude(exclude);
+
+ 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);
+ String deferredValueType = getString(clazz, "deferredValueType", props, null);
+ String deferredMethodSignature = getString(clazz, "deferredMethodSignature", props, null);
+ Boolean exclude = getBoolean(clazz, "exclude", props, null);
+
+ AttributeMeta a = new AttributeMeta();
+ a.setName(name);
+ a.setClassName(className);
+ a.setRequired(required);
+ a.setRtexprvalue(rtexprvalue);
+ a.setDescription(shortDescription);
+ a.setLongDescription(longDescription);
+ a.setDeferredValueType(deferredValueType);
+ a.setDeferredMethodSignature(deferredMethodSignature);
+ a.setExclude(exclude);
+
+ 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, (AbstractJavaEntity)tag.getContext(), clazz,
+ method, component);
+ }
+
+ Annotation anno = getAnnotation(method, DOC_PROPERTY);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processComponentProperty(props, (AbstractJavaEntity)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, (AbstractJavaEntity)tag.getContext(),
+ clazz, intfmethod, component);
+ }
+
+ Annotation anno = getAnnotation(intfmethod, DOC_PROPERTY);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processInterfaceComponentProperty(props, (AbstractJavaEntity)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, (AbstractJavaEntity)tag.getContext(), clazz,
+ component);
+ }
+
+ Annotation jspPropertyAnno = getAnnotation(clazz, DOC_JSP_PROPERTY);
+ if (jspPropertyAnno != null)
+ {
+ Map props = jspPropertyAnno.getNamedParameterMap();
+ processComponentJspProperty(props, (AbstractJavaEntity)jspPropertyAnno.getContext(),
+ clazz, component);
+ }
+
+
+ Annotation jspAnno = getAnnotation(clazz, DOC_JSP_PROPERTIES);
+ if (jspAnno != null)
+ {
+ Object jspProps = jspAnno.getNamedParameter("properties");
+
+ if (jspProps instanceof Annotation)
+ {
+ Annotation jspPropertiesAnno = (Annotation) jspProps;
+ Map props = jspPropertiesAnno.getNamedParameterMap();
+ processComponentJspProperty(props, (AbstractJavaEntity)jspAnno.getContext(), clazz,
+ component);
+ }
+ else
+ {
+ List jspPropsList = (List) jspProps;
+ for (int i = 0; i < jspPropsList.size();i++)
+ {
+ Annotation anno = (Annotation) jspPropsList.get(i);
+
+ Map props = anno.getNamedParameterMap();
+ processComponentJspProperty(props, (AbstractJavaEntity)jspAnno.getContext(), clazz,
+ component);
+ }
+ }
+
+ }
+ }
+
+ 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, (AbstractJavaEntity)tag.getContext(), clazz,
+ method, component);
+ }
+
+ Annotation anno = getAnnotation(method, DOC_FACET);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processComponentFacet(props, (AbstractJavaEntity)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, (AbstractJavaEntity)tag.getContext(),
+ clazz, intfmethod, component);
+ }
+
+ Annotation anno = getAnnotation(intfmethod, DOC_FACET);
+ if (anno != null)
+ {
+ Map props = anno.getNamedParameterMap();
+ processInterfaceComponentFacet(props, (AbstractJavaEntity)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);
+ String deferredValueType = getString(clazz, "deferredValueType", props, null);
+
+ Type returnType = null;
+
+ if (method.getName().startsWith("set"))
+ {
+ returnType = method.getParameters()[0].getType();
+ }
+ else
+ {
+ returnType = method.getReturns();
+ }
+
+ String fullyQualifiedReturnType = returnType.getJavaClass().getFullyQualifiedName();
+
+ fullyQualifiedReturnType = getFullyQualifiedClassName(clazz, fullyQualifiedReturnType);
+
+ if (returnType.isArray() && (fullyQualifiedReturnType.indexOf('[') == -1))
+ {
+ for (int i = 0; i < returnType.getDimensions();i++)
+ {
+ fullyQualifiedReturnType = fullyQualifiedReturnType + "[]";
+ }
+ }
+
+ PropertyMeta p = new PropertyMeta();
+ p.setName(methodToPropName(method.getName()));
+ p.setClassName(fullyQualifiedReturnType);
+ 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.setDeferredValueType(deferredValueType);
+ 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..ca146cd
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/unpack/UnpackMojo.java
@@ -0,0 +1,448 @@
+/*
+ * 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.
+ * <p>
+ * This mojo reutilize org.apache.maven.plugin.dependency.fromConfiguration.UnpackMojo
+ * from maven-dependency-plugin.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * This plugin works as unpack goal of maven-dependency-plugin with 2 additional
+ * enhancements:
+ * </p>
+ * <ol>
+ * <li>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.</li>
+ * <li>If a file is generated from the model (reading the myfaces-metadata.xml) it is not
+ * copied, since this should be generated again.</li>
+ * </ol>
+ *
+ * @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..21faac3
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/facelets-taglib.vm
@@ -0,0 +1,103 @@
+<?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())
+#if ($utils.getTagPrefix($component.name) == $shortname)
+ <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
+#end
+
+ <!-- Converter tags -->
+#set ($componentList = ${model.getConverters()})
+#foreach( $component in $componentList )
+#if ($modelIds.contains($component.modelId)
+ && ($component.name))
+#if ($component.converterId)
+#if ($utils.getTagPrefix($component.name) == $shortname)
+ <tag>
+ <tag-name>$utils.getTagName($component.name)</tag-name>
+ <converter>
+ <converter-id>$component.converterId</converter-id>
+ </converter>
+ </tag>
+#end
+#end
+#end
+#end
+
+ <!-- Validator tags -->
+#set ($componentList = ${model.getValidators()})
+#foreach( $component in $componentList )
+#if ($modelIds.contains($component.modelId)
+ && ($component.name))
+#if ($component.validatorId)
+#if ($utils.getTagPrefix($component.name) == $shortname)
+ <tag>
+ <tag-name>$utils.getTagName($component.name)</tag-name>
+ <validator>
+ <validator-id>$component.validatorId</validator-id>
+ </validator>
+ </tag>
+#end
+#end
+#end
+#end
+
+ <!-- Single Tags -->
+#set ($tagList = $model.getTags())
+#foreach( $tag in $tagList )
+#if ($modelIds.contains($tag.modelId))
+#if ($tag.tagHandler)
+#if ($utils.getTagPrefix($tag.name) == $shortname)
+ <tag>
+ <tag-name>$utils.getTagName($tag.name)</tag-name>
+ <handler-class>$tag.tagHandler</handler-class>
+ </tag>
+#end
+#end
+#end
+#end
+
+</facelet-taglib>
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..7c9fb6a
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/tagClass12.vm
@@ -0,0 +1,179 @@
+// 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))
+#if ($property.isLiteralOnly() && $property.className == "boolean")
+#set ($type = "String")
+#end
+ 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 ($property.isLiteralOnly() && $property.className == "boolean")
+#set ($type = "String")
+#end
+#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
+#if ($utils.isPrimitiveClass($property.className))## 4
+ comp.getAttributes().put("$property.name", ${utils.getBoxedClass($property.className)}.valueOf($field));
+#else## 4
+ comp.getAttributes().put("$property.name", $field);
+#end## 4
+#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)
+#set ($empty = "null")
+ $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..8e62161
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/tomahawk12.vm
@@ -0,0 +1,229 @@
+<?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
+#if ( "$!property.isRtexprvalue()" == "")
+#set ($type = $utils.getClassFromFullClass($property.className))
+#if ($type == "String")
+ <deferred-value></deferred-value>
+#else
+ <deferred-value>
+ <type>$property.className</type>
+ </deferred-value>
+#end
+#else
+ <rtexprvalue>$property.isRtexprvalue().booleanValue()</rtexprvalue>
+#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/trinidad-faces-config12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/trinidad-faces-config12.vm
new file mode 100644
index 0000000..1f12877
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/trinidad-faces-config12.vm
@@ -0,0 +1,176 @@
+<?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.isConfigExcluded()))
+ <component>
+#if ($component.longDescription)
+ <description><![CDATA[$component.longDescription]]></description>
+#end
+ <component-type>$component.type</component-type>
+ <component-class>$component.className</component-class>
+#set ($facetList = ${component.facetList})
+#foreach( $facet in $facetList )
+ <facet>
+#if ($facet.longDescription)
+ <description><![CDATA[$facet.longDescription]]></description>
+#end
+ <facet-name>$facet.name</facet-name>
+ </facet>
+#end
+#set ($propertyList = ${component.propertyList})
+#foreach( $property in $propertyList )
+## Theorically, it should only add properties visible on tld or transient
+## (not visible on tld but used on renderers like "transient").
+## On myfaces core 1.2, only "transient" property use it.
+## But inclusive, some tagExcluded properties belongs to the
+## component class or are used by some reason (for example in UIInput
+## valid, localValueSet or submittedValue).
+## Anyway, this information works only as metadata.
+#if (!$property.name.equals("binding")) ## binding is used only in tag class or tag handler
+## !$property.isTagExcluded() || $property.isTransient()
+#if ( true )
+ <property>
+#if ($property.longDescription)
+ <description><![CDATA[$property.longDescription]]></description>
+#end
+ <property-name>$property.name</property-name>
+ <property-class>$property.className</property-class>
+#if($utils.getDefaultValueField($property))
+#set ($defaultValue = $utils.getDefaultValueField($property))
+#if ($defaultValue.charAt(0) == '"')
+#set ($dVsize = $defaultValue.length() - 1)
+#set ($defaultValue = $defaultValue.substring(1,$dVsize) )
+#end
+ <default-value>$defaultValue</default-value>
+#end
+ </property>
+#end
+#end
+#end
+## <component-extension>
+## <component-family>$component.family</component-family>
+###if ($component.rendererType)
+###if (!($component.rendererType == ""))
+## <renderer-type>$component.rendererType</renderer-type>
+###end
+###end
+## </component-extension>
+ </component>
+#end
+#end
+#set ($converterList = ${model.getConverters()})
+#foreach( $converter in $converterList )
+#if ($modelIds.contains($converter.modelId)
+ && !($converter.isConfigExcluded()))
+ <converter>
+#if ($converter.longDescription)
+ <description><![CDATA[$converter.longDescription]]></description>
+#end
+ <converter-id>$converter.converterId</converter-id>
+ <converter-class>$converter.className</converter-class>
+#set ($propertyList = ${converter.propertyList})
+#foreach( $property in $propertyList )
+#if (!$property.name.equals("binding")) ## binding is used only in tag class or tag handler
+ <property>
+#if ($property.longDescription)
+ <description><![CDATA[$property.longDescription]]></description>
+#end
+ <property-name>$property.name</property-name>
+ <property-class>$property.className</property-class>
+#if($utils.getDefaultValueField($property))
+#set ($defaultValue = $utils.getDefaultValueField($property))
+#if ($defaultValue.charAt(0) == '"')
+#set ($dVsize = $defaultValue.length() - 1)
+#set ($defaultValue = $defaultValue.substring(1,$dVsize) )
+#end
+ <default-value>$defaultValue</default-value>
+#end
+ </property>
+#end
+#end
+ </converter>
+#end
+#end
+#set ($validatorList = ${model.getValidators()})
+#foreach( $validator in $validatorList )
+#if ($modelIds.contains($validator.modelId) &&
+ !($validator.isConfigExcluded().booleanValue()) &&
+ $validator.validatorId)
+ <validator>
+#if ($validator.longDescription)
+ <description><![CDATA[$validator.longDescription]]></description>
+#end
+#if ($validator.name)
+ <display-name>$utils.getTagName($validator.name)</display-name>
+#end
+ <validator-id>$validator.validatorId</validator-id>
+ <validator-class>$validator.className</validator-class>
+#set ($propertyList = ${validator.propertyList})
+#foreach( $property in $propertyList )
+#if (!$property.name.equals("binding")) ## binding is used only in tag class or tag handler
+ <property>
+#if ($property.longDescription)
+ <description><![CDATA[$property.longDescription]]></description>
+#end
+ <property-name>$property.name</property-name>
+ <property-class>$property.className</property-class>
+#if($utils.getDefaultValueField($property))
+#set ($defaultValue = $utils.getDefaultValueField($property))
+#if ($defaultValue.charAt(0) == '"')
+#set ($dVsize = $defaultValue.length() - 1)
+#set ($defaultValue = $defaultValue.substring(1,$dVsize) )
+#end
+ <default-value>$defaultValue</default-value>
+#end
+ </property>
+#end
+#end
+ </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/trinidad-tld12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/trinidad-tld12.vm
new file mode 100644
index 0000000..6cde7e0
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/trinidad-tld12.vm
@@ -0,0 +1,249 @@
+<?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>$version</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
+#if ( "$!property.isRtexprvalue()" == "")
+#set ($type = $utils.getClassFromFullClass($property.className))
+#if ($type == "String" || $type == "String[]" || $type == "Object" || $type == "List" || $type == "Date" || $type == "RowKeySet" || $type == "int[]")
+ <deferred-value></deferred-value>
+#else
+ <deferred-value>
+ <type>$property.className</type>
+ </deferred-value>
+#end
+#else
+ <rtexprvalue>$property.isRtexprvalue().booleanValue()</rtexprvalue>
+#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
+#if ($component.longDescription)
+ <description><![CDATA[$component.longDescription]]></description>
+#end
+
+ <attribute>
+ <name>id</name>
+ </attribute>
+#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" || $type == "String[]" || $type == "Object" || $type == "List" || $type == "Date" || $type == "RowKeySet" || $type == "int[]" || $type == "Locale" || $type == "TimeZone")
+ <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>
+
+ <attribute>
+ <name>id</name>
+ </attribute>
+#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" || $type == "String[]" || $type == "Object" || $type == "List" || $type == "Date" || $type == "RowKeySet" || $type == "int[]" || $type == "DateListProvider")
+ <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>
+#if ($tag.longDescription)
+ <description><![CDATA[$tag.longDescription]]></description>
+#end
+#set ($attributeList = ${tag.attributeList})
+#foreach( $attribute in $attributeList )
+#if (!$attribute.isExclude().booleanValue())
+ <attribute>
+ <name>$attribute.name</name>
+#if ($attribute.isRequired())
+ <required>$attribute.isRequired()</required>
+#end
+#set ($type = $utils.getClassFromFullClass($attribute.className))
+#if ($type == "MethodExpression")
+ <deferred-method>
+ <method-signature>${attribute.deferredMethodSignature}</method-signature>
+ </deferred-method>
+#elseif ($type == "ValueExpression")
+ <deferred-value>#if($attribute.deferredValueType)$attribute.deferredValueType#end</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
+#end
+ </tag>
+#end
+#end
+</taglib>
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/trinidadComponentClass12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/trinidadComponentClass12.vm
new file mode 100644
index 0000000..6947e1b
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/trinidadComponentClass12.vm
@@ -0,0 +1,210 @@
+## Velocity template used to generate trinidad 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.
+##
+/*
+ * 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 java.util.HashMap;
+import java.util.Map;
+
+import javax.el.ValueExpression;
+import javax.faces.context.FacesContext;
+$utils.importTagClasses($component)
+
+import org.apache.myfaces.trinidad.bean.FacesBean;
+import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.util.ComponentUtils;
+
+#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 FacesBean.Type TYPE = new FacesBean.Type(
+ ${generatedClassParent}.TYPE);
+#set ($propertyList = ${component.propertyComponentList})
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $utils.getClassFromFullClass($property.className))
+#set ($key = $utils.getConstantNameFromProperty($property.name , "_KEY"))
+##
+## CALCULATE DEFAULT VALUE
+##
+#if($utils.getDefaultValueField($property))
+#set ($defaultValue = $utils.getDefaultValueField($property))
+#if ($defaultValue == "true")
+#set ($defaultValue = "Boolean.TRUE")
+#end
+#if ($defaultValue == "false")
+#set ($defaultValue = "Boolean.FALSE")
+#end
+#if ($type == "char")
+#set ($defaultValue = "'"+$defaultValue+"'")
+#end
+#else
+#set ($defaultValue = false)
+#end
+## CALCULATE CAPABILITIES
+#set ($caps = "")
+#set ($capsCount = 0)
+#if ($property.isMethodBinding() || $property.isLiteralOnly())
+#set ($capsCount = $capsCount + 1)
+#end
+#if ($property.isStateHolder())
+#set ($capsCount = $capsCount + 1)
+#end
+#if ($property.isTransient())
+#set ($capsCount = $capsCount + 1)
+#end
+#if ($property.isMethodBinding() || $property.isLiteralOnly())
+#set ($caps = $caps + "PropertyKey.CAP_NOT_BOUND")
+#if ($capsCount > 1)#set($capsCount = $capsCount - 1)#set($caps=$caps+" | ")#end
+#end
+#if ($property.isStateHolder())
+#set ($caps = $caps + "PropertyKey.CAP_STATE_HOLDER")
+#if ($capsCount > 1)#set($capsCount = $capsCount - 1)#set($caps=$caps+" | ")#end
+#end
+#if ($property.isTransient())
+#set ($caps = $caps + "PropertyKey.CAP_TRANSIENT")
+#if ($capsCount > 1)#set($capsCount = $capsCount - 1)#set($caps=$caps+" | ")#end
+#end
+## This template does not handle PropertyKey.CAP_LIST
+
+ static public final PropertyKey $key =
+ TYPE.registerKey(
+ "$property.name",#if($utils.isPrimitiveClass($type))${utils.getBoxedClass($type)}.class#{else}${type}.class#end
+#if($defaultValue),${defaultValue}#end
+#if ( !$caps.equals("")),${caps}#end);
+#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 == "")
+ super(null);
+#else
+ super("$component.rendererType");
+#end
+#else
+ super(null);
+#end
+ }
+
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $utils.getClassFromFullClass($property.className))
+#set ($key = $utils.getConstantNameFromProperty($property.name , "_KEY"))
+
+ final public $type $utils.getMethodReaderFromProperty($property.name, $type)()
+ {
+#if ($utils.isPrimitiveClass($type))
+#if ($type == "char")
+ return ComponentUtils.resolveCharacter((Character) getProperty($key));
+#elseif ($type == "byte" || $type == "short")
+## There is no ComponentUtils remethod, so we just cast it.
+ return $utils.castIfNecessary($type) getProperty($key);
+#else
+ return ComponentUtils.resolve${utils.getBoxedClass($type)}(getProperty($key));
+#end
+#elseif ($type == "String" || $type == "Locale" || $type == "TimeZone")
+ return ComponentUtils.resolve${utils.getBoxedClass($type)}(getProperty($key));
+#else
+ return $utils.castIfNecessary($type) getProperty($key);
+#end
+ }
+
+ final public void $utils.getPrefixedPropertyName("set", $property.name)($type $utils.getVariableFromName($property.name))
+ {
+#if ($utils.isPrimitiveClass($type))
+#if ($type == "boolean")
+ setProperty($key, $utils.getVariableFromName($property.name) ? Boolean.TRUE : Boolean.FALSE);
+#else
+ setProperty($key, ${utils.getBoxedClass($type)}.valueOf( $utils.getVariableFromName($property.name) ));
+#end
+#else
+ setProperty($key, $utils.getVariableFromName($property.name));
+#end
+ }
+#end
+
+ @Override
+ public String getFamily()
+ {
+ return COMPONENT_FAMILY;
+ }
+
+ @Override
+ protected FacesBean.Type getBeanType()
+ {
+ return TYPE;
+ }
+
+ public ${utils.getClassFromFullClass($component.className)}(String rendererType)
+ {
+ super(rendererType);
+ }
+
+ static
+ {
+ TYPE.lock();
+ }
+}
diff --git a/myfaces-builder-plugin/src/main/resources/META-INF/trinidadTagClass12.vm b/myfaces-builder-plugin/src/main/resources/META-INF/trinidadTagClass12.vm
new file mode 100644
index 0000000..4fa66f1
--- /dev/null
+++ b/myfaces-builder-plugin/src/main/resources/META-INF/trinidadTagClass12.vm
@@ -0,0 +1,142 @@
+// 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.el.ValueExpression;
+import org.apache.myfaces.trinidad.bean.FacesBean;
+##$utils.importTagClasses12($component)
+#set ($addMeMb = false)
+#set ($addMe = false)
+#set ($propertyList = ${component.propertyTagList})
+#foreach( $property in $propertyList )
+#if ($property.isMethodExpression())
+#set ($addMe = true)
+#end
+#if ($property.isMethodBinding())
+#set ($addMeMb = true)
+#end
+#end
+#if ($addMe)
+import javax.el.MethodExpression;
+#end
+#if ($addMeMb)
+import org.apache.myfaces.trinidadinternal.taglib.util.MethodExpressionMethodBinding;
+#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.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
+ }
+
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $utils.getJspPropertyType12($property))
+#if ($property.isLiteralOnly() && $property.className == "boolean")
+#set ($type = "String")
+#end
+ private $type $field;
+
+#set ($var = $utils.getVariableFromName($property.name))
+ public void $utils.getPrefixedPropertyName("set", $property.jspName)($type $var)
+ {
+ $field = $var;
+ }
+#end
+
+ @Override
+ protected void setProperties(
+ FacesBean bean)
+ {
+ super.setProperties(bean);
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($type = $utils.getClassFromFullClass($property.className))
+#set ($key = $utils.getConstantNameFromProperty($property.name , "_KEY"))
+#if ($utils.isConverter($property.className))## 2
+ if ($field != null)
+ {
+ if (!${field}.isLiteralText())
+ {
+ bean.setValueExpression(${component.className}.${key}, $field);
+ }
+ else
+ {
+ String s = ${field}.getExpressionString();
+ if (s != null)
+ {
+ Converter converter = getFacesContext().getApplication().createConverter(s);
+ bean.setProperty(${component.className}.${key}, converter);
+ }
+ }
+ }
+#elseif ($property.isMethodExpression())
+ bean.setProperty(${component.className}.${key}, $field);
+#elseif ($property.isMethodBinding())
+ if ($field != null)
+ bean.setProperty(${component.className}.${key}, new MethodExpressionMethodBinding($field))
+#elseif ($property.isLiteralOnly())
+ bean.setProperty(${component.className}.${key}, $field);
+#elseif ($type == "String[]")
+ setStringArrayProperty(bean, ${component.className}.${key}, $field);
+#else
+ setProperty(bean, ${component.className}.${key}, $field);
+#end
+#end
+ }
+
+ public void release()
+ {
+ super.release();
+#foreach( $property in $propertyList )
+#set ($field = $property.fieldName)
+#set ($empty = "null")
+ $field = $empty;
+#end
+ }
+}
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><${component.name}></title>
+ </properties>
+ <body>
+ <section name="Summary">
+ <p>
+ <b>Tag name:</b> <${component.name}>
+ <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><${converter.name}></title>
+ </properties>
+ <body>
+ <section name="Summary">
+ <p>
+ <b>Tag name:</b> <${converter.name}>
+ <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><${tag.name}></title>
+ </properties>
+ <body>
+ <section name="Summary">
+ <p>
+ <b>Tag name:</b> <${tag.name}>
+ <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><${validator.name}></title>
+ </properties>
+ <body>
+ <section name="Summary">
+ <p>
+ <b>Tag name:</b> <${validator.name}>
+ <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/attributes.apt b/myfaces-builder-plugin/src/site/apt/attributes.apt
new file mode 100644
index 0000000..fe5b9a7
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/attributes.apt
@@ -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.
+
+ ------
+ Attributes
+ ------
+
+Attributes
+
+ Tags has attributes. Attribute behavior is different from a property,
+ so it is necessary to use a different annotation/doclet to use it.
+ Usually tags are written by users, but has few attributes and does not
+ have a complex hierarchy, so it is not necessary make tags inherit
+ attributes from other tags.
+
+ The objective of use @JSFJspTag and @JSFJspAttribute annotation/doclet is
+ make easier keep synchronized the .tld file with the tag class.
+
+* Attribute loaded from basic type
+
+ On jsf 1.1 and in some special cases, no ValueExpressions are allowed
+ on some attribute.
+
+-------------------
+ /**
+ * On tlds this is translated to something like:
+ *
+ * <attribute>
+ * <description><![CDATA[Some description]]></description>
+ * <name>var</name>
+ * <required>false</required>
+ * <rtexprvalue>false</rtexprvalue>
+ * <type>java.lang.String</type>
+ * </attribute>
+ *
+ */
+ @JSFJspAttribute
+ public void setVar(String var)
+ {
+ // .... some code ....
+ }
+-------------------
+
+* Attribute loaded from ValueExpression
+
+ There are two cases
+
+-------------------
+
+ /**
+ * On jsf 1.1 this translates to something like:
+ *
+ * Works on version 1.0.2, but some jsf 1.2 tld templates translate it to:
+ *
+ * <attribute>
+ * <description><![CDATA[The fully qualified class name of the ActionListener class.]]></description>
+ * <name>type</name>
+ * <required>false</required>
+ * <deferred-value>
+ * <type>java.lang.String</type>
+ * </deferred-value>
+ * </attribute>
+ *
+ * On version 1.0.3 this should be translated to something like:
+ *
+ * <attribute>
+ * <description><![CDATA[The fully qualified class name of the ActionListener class.]]></description>
+ * <name>type</name>
+ * <required>false</required>
+ * <rtexprvalue>true</rtexprvalue>
+ * </attribute>
+ *
+ * But this depends on the template used to generate its tld.
+ **/
+ @JSFJspAttribute(className = "java.lang.String", rtexprvalue = true)
+ public void setType(ValueExpression type)
+ {
+ // .... some code ....
+ }
+
+ /**
+ * Works on version 1.0.3 and upper for jsf 1.2 and upper tld templates:
+ *
+ * <attribute>
+ * <description><![CDATA[The fully qualified class name of the ActionListener class.]]></description>
+ * <name>type</name>
+ * <required>false</required>
+ * <deferred-value>
+ * <type>java.lang.String</type>
+ * </deferred-value>
+ * </attribute>
+ **/
+ @JSFJspAttribute(deferredValueType = "java.lang.String")
+ public void setType(ValueExpression type)
+ {
+ // .... some code ....
+ }
+
+
+-------------------
+
+* Attribute loaded from MethodExpression
+
+-------------------
+ /** works on version 1.0.3 and upper for jsf 1.2 and upper tld templates **/
+ @JSFJspAttribute(required=true,
+ deferredMethodSignature = "void myMethod(javax.faces.context.FacesContext, java.io.OutputStream)")
+ public void setMethod(MethodExpression method)
+ {
+ _method = method;
+ }
+-------------------
diff --git a/myfaces-builder-plugin/src/site/apt/components.apt b/myfaces-builder-plugin/src/site/apt/components.apt
new file mode 100644
index 0000000..845d019
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/components.apt
@@ -0,0 +1,240 @@
+ ~~ 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.
+
+ ------
+ Creating Custom Components
+ ------
+
+Creating Custom Components
+
+ Any JSF Component has the following elements:
+
+ * Component class file(s).
+
+ * JSP tag class file(s).
+
+ * Entry on faces-config.xml.
+
+ * Renderer class file(s) (optional).
+
+ * TLD file (optional).
+
+ * facelet-taglib entry (optional).
+
+ * Facelets tag handler files (optional).
+
+ Keep all those files up to date is a complex task, but with
+ myfaces-builder-plugin you just need to take care about:
+
+ * Component class file(s).
+
+ * Renderer class file(s) (optional).
+
+ * Facelets tag handler files (optional).
+
+ This example shows step by step what do you need to create a custom
+ component.
+
+Setting up your project
+
+ All information related can be found {{{setup.html}here}}.
+
+Configuration files (faces-config.xml, .tld, facelets taglib)
+
+ This {{{config-files.html}page}} shows some examples.
+
+Writing your component class
+
+ There are three possibilities for create a component class:
+
+ * Write just one file and add all code manually (Example: t:aliasBean).
+
+ * Write an abstract class, and let generate all property code, including
+ saveState/restoreState methods in a concrete child class
+ (Example: almost all components in tomahawk core and sandbox).
+
+ * Write an abstract class (generally package scope) and use template
+ pattern. In other words, all property code is generated including
+ saveState/restoreState methods in a concrete child class, but other
+ code inside the abstract class is copied to the generated class.
+
+* Write a component class manually
+
+ In this mode, no code is generated, but the information is chained to
+ other files to be generated like faces-config.xml, tlds, tag classes, etc.
+
+ Below there is an example of it:
+
+-------------------
+/**
+ * The most important points are:
+ *
+ * 1. Define componentType, componentFamily and rendererType adding its
+ * constants (like below) or directly in the annotation.
+ *
+ * 2. If the component has a jsp tag, define the "name" and the "tagClass"
+ * If the tagClass does not exists a new file is generated if make-tags
+ * goal is set on pom.xml
+ *
+ */
+@JSFComponent(
+ name = "mycomponents:sayHello",
+ clazz = "org.myorganization.component.sayhello.SayHello",
+ tagClass = "org.myorganization.component.sayhello.SayHelloTag")
+public class SayHello extends UIOutput
+{
+ public static final String COMPONENT_TYPE = "org.myorganization.SayHello";
+ public static final String DEFAULT_RENDERER_TYPE = "org.myorganization.SayHelloRenderer";
+ public static final String COMPONENT_FAMILY = "javax.faces.Output";
+
+ /** ..... Some custom code goes here .... **/
+}
+-------------------
+
+* Write a component class using Abstract Pattern
+
+ The objective is create a abstract component class
+ that defines all information required to generate the concrete
+ component class. All custom code goes in the abstract class, so it
+ is inherited to the child component.
+
+ This pattern is preferred over template mode, because it is more simple
+ to understand, but there are some cases where this mode cannot be
+ applied (like in myfaces core api, where the component hierarchy cannot
+ be changed).
+
+ Below there is an example of it:
+
+-------------------
+/**
+ * To generate component classes using abstract pattern
+ *
+ * 1. Define the "clazz" file which it is generated
+ *
+ * 2. Define componentType, componentFamily and rendererType adding its
+ * constants (like below) or directly in the annotation.
+ *
+ * 3. If the component has a jsp tag, define the "name" and the "tagClass"
+ * If the tagClass does not exists a new file is generated if make-tags
+ * goal is set on pom.xml
+ *
+ */
+@JSFComponent(
+ name = "mycomponents:sayHello",
+ clazz = "org.myorganization.component.sayhello.SayHello",
+ tagClass = "org.myorganization.component.sayhello.SayHelloTag")
+public abstract class AbstractSayHello extends UIOutput
+{
+ public static final String COMPONENT_TYPE = "org.myorganization.SayHello";
+ public static final String DEFAULT_RENDERER_TYPE = "org.myorganization.SayHelloRenderer";
+ public static final String COMPONENT_FAMILY = "javax.faces.Output";
+
+ /**
+ * User's first name.
+ */
+ @JSFProperty
+ public abstract String getName();
+}
+-------------------
+
+* Write a component class using Template Pattern
+
+ The objective is create an abstract (generally package scoped) class
+ that works as a "template".
+
+-------------------
+@JSFComponent(
+ name = "mycomponents:sayHello",
+ clazz = "org.myorganization.component.sayhello.SayHello",
+ tagClass = "org.myorganization.component.sayhello.SayHelloTag")
+abstract class _SayHello extends UIOutput
+{
+ public static final String COMPONENT_TYPE = "org.myorganization.SayHello";
+ public static final String DEFAULT_RENDERER_TYPE = "org.myorganization.SayHelloRenderer";
+ public static final String COMPONENT_FAMILY = "javax.faces.Output";
+
+ /**
+ * This method is copied to generated SayHello class
+ **/
+ public void broadcast(javax.faces.event.FacesEvent event)
+ throws javax.faces.event.AbortProcessingException
+ {
+ //Some custom code goes here
+ }
+
+ /**
+ * This method is not copied, but @JSFExclude works with fields too!
+ **/
+ @JSFExclude
+ public void doSomething()
+ {
+ //Some never used custom code goes here
+ }
+
+ /**
+ * User's first name.
+ */
+ @JSFProperty
+ public abstract String getName();
+}
+-------------------
+
+Generating Component Tag Classes
+
+ The goal "make-tags" trigger component jsp tag generation. This goal
+ checks if the tag class exists and if not, it creates one.
+
+ Here there are two scenarios:
+
+ * The component class inherits from jsf core UIXXXXX, so the generated
+ class inherits from javax.faces.webapp.UIComponent(EL)Tag.
+
+ * The component class inherits from jsf core HtmlXXX. In this case,
+ the tag classes where your component inherits is on myfaces core
+ impl jar, so again there are three options:
+
+ * Add myfaces core impl jar as compile dependency and use myfaces
+ core in your web application.
+
+ * Add tomahawk core or core12 to your dependencies, where there
+ is an alternate tag hierarchy, so your components can work
+ with the reference implementation. Make sure tomahawk dependency.
+ should be before myfaces core dependency in the pom, to be sure
+ that tomahawk model is loaded first.
+
+ * Generate a jsf html tag hierarchy in your jar. See tomahawk core
+ or core12 pom for details.
+
+ If you need to write some custom code on tag class, but keep some
+ code generated, use abstract pattern on tag class. The properties that
+ needs to be defined on abstract tag class must have inheritedTag="true",
+ so there are not overriden. See t:tree component for an example.
+
+Adding a Renderer to faces-config.xml file.
+
+ The annotations/doclets @JSFRenderer and @JSFRenderKit are used include
+ renderer configuration to generated faces-config.xml files. Just add it
+ to your renderer like this:
+
+---------------------------
+@JSFRenderer(
+ renderKitId = "HTML_BASIC",
+ family = "javax.faces.Output",
+ type = "org.myorganization.SayHelloRenderer")
+public class SayHelloRenderer extends Renderer
+{
+ //Some code goes here
+}
+---------------------------
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/site/apt/config-files.apt b/myfaces-builder-plugin/src/site/apt/config-files.apt
new file mode 100644
index 0000000..9e537d7
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/config-files.apt
@@ -0,0 +1,84 @@
+ ~~ 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.
+
+ ------
+ Configuration files
+ ------
+
+Configuration files (faces-config.xml, .tld, facelets taglib)
+
+ All configuration files are generated by
+ {{{make-config-mojo.html}make-config}} goal.
+
+ This goal can be seen as an equation:
+
+-------------------------
+ xmlBaseFile + templateFile( model(s) to take in consideration ) = xmlFile
+-------------------------
+
+ It is enought flexible to generate any file based on the model.
+ Some examples can be seen below.
+
+-------------------------
+ ............ plugin declaration goes before ...........
+ <!-- faces-config -->
+ <execution>
+ <id>makefacesconfig</id>
+ <configuration>
+ <templateFile>faces-config12.vm</templateFile>
+ <xmlFile>META-INF/faces-config.xml</xmlFile>
+ </configuration>
+ <goals>
+ <goal>make-config</goal>
+ </goals>
+ </execution>
+
+ <!-- tld -->
+ <execution>
+ <id>maketomahawktld</id>
+ <configuration>
+ <xmlFile>META-INF/tomahawk.tld</xmlFile>
+ <xmlBaseFile>src/main/conf/META-INF/tomahawk-base.tld</xmlBaseFile>
+ <templateFile>tomahawk12.vm</templateFile>
+ <params>
+ <shortname>t</shortname>
+ <uri>http://myfaces.apache.org/tomahawk</uri>
+ <displayname>Tomahawk tag library 1.2.</displayname>
+ </params>
+ </configuration>
+ <goals>
+ <goal>make-config</goal>
+ </goals>
+ </execution>
+
+ <!-- facelets taglib -->
+ <execution>
+ <id>maketomahawktaglib</id>
+ <configuration>
+ <xmlFile>META-INF/tomahawk.taglib.xml</xmlFile>
+ <xmlBaseFile>src/main/conf/META-INF/facelets-taglib-base.xml</xmlBaseFile>
+ <templateFile>facelets-taglib.vm</templateFile>
+ <params>
+ <shortname>t</shortname>
+ <uri>http://myfaces.apache.org/tomahawk</uri>
+ </params>
+ </configuration>
+ <goals>
+ <goal>make-config</goal>
+ </goals>
+ </execution>
+ .................
+-------------------------
+
diff --git a/myfaces-builder-plugin/src/site/apt/converters.apt b/myfaces-builder-plugin/src/site/apt/converters.apt
new file mode 100644
index 0000000..4c3761a
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/converters.apt
@@ -0,0 +1,75 @@
+ ~~ 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.
+
+ ------
+ Creating Custom Converters
+ ------
+
+Creating Custom Converters
+
+ A JSF Converter needs the following elements:
+
+ * A class implementing converter interface.
+
+ * Entry on faces-config.xml.
+
+ * Tag entry on tld.
+
+ * Tag entry on facelets taglib (optional).
+
+ * JSP Tag class
+
+ Myfaces builder plugin provide annotations/doclets to help users maintain
+ configuration files, and generating converter jsp tag classes
+ automatically. In this way, all information for a converter is just in
+ one file (the class implementing Converter interface).
+
+ On jsf 1.2, it is necessary to provide a base tag class that extends
+ from javax.faces.webapp.ConverterELTag where all converters should
+ inherit. This class is on myfaces commons converters project, but
+ users can provide custom template implementations for it.
+
+Setting up your project
+
+ All information related can be found {{{setup.html}here}}.
+
+Configuration files (faces-config.xml, .tld, facelets taglib)
+
+ This {{{config-files.html}page}} shows some examples.
+
+Annotate Converter Classes
+
+ Just add the annotations/doclets as presented below:
+
+-------------------
+
+@JSFConverter(
+ name = "mcc:convertDateTime",
+ tagClass = "org.apache.myfaces.commons.converter.ConvertDateTimeTag",
+ tagSuperclass = "org.apache.myfaces.commons.converter.ConverterTag")
+public class DateTimeConverter extends javax.faces.convert.DateTimeConverter
+{
+ public static final String CONVERTER_ID = "org.apache.myfaces.custom.convertDateTime.DateTimeConverter";
+
+ /** .......... impl code goes here ......... **/
+
+ @JSFProperty
+ public String getProperty()
+ {
+ // some stuff
+ }
+}
+-------------------
+
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/site/apt/doclets-annotations.apt b/myfaces-builder-plugin/src/site/apt/doclets-annotations.apt
new file mode 100644
index 0000000..880fd96
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/doclets-annotations.apt
@@ -0,0 +1,70 @@
+ ~~ 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.
+
+ ------
+ Doclets and Annotations
+ ------
+
+Doclets and Annotations
+
+ To annotate the necessary information in
+ component / converter / validator / renderkit / renderer / tag files
+ you can use doclets:
+
+-------------------
+
+ /**
+ * This is a doclet
+ *
+ * @JSFProperty
+ * required = "true"
+ * defaultValue = "AnyValue"
+ **/
+
+-------------------
+
+ or annotations
+
+-------------------
+
+ /**
+ * This is an annotation
+ *
+ **/
+ @JSFProperty(
+ required = true,
+ defaultValue = "AnyValue")
+
+-------------------
+
+ Doclets and annotations can be used on both jsf 1.1 and jsf 1.2, but
+ since jsf 1.1 is jdk 1.4 compatible, it is preferred to use doclets with
+ jsf 1.1 (note that if you use annotations, your source code should be
+ jdk 1.5 in order to compile).
+
+ The differences between doclets and annotations are listed below:
+
+ * Attribute names like "class", "implements" in annotated
+ version are "clazz" and "implementz".
+
+ * All attribute values in doclets must be between "". In annotations
+ boolean attributes must not (see "required" example below).
+
+ * Usage of annotations like @JSFJspProperties and @JSFRenderers are
+ not required on doclets.
+
+ Taking into account the previous differences, you can consult the
+ annotation javadoc for doclets.
+
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..ef80273
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/howto.apt
@@ -0,0 +1,100 @@
+ ~~ 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.
+
+ ------
+ How to Use
+ ------
+
+Scan annotations/doclets and generate metadata
+
+ Just add this code to your project pom.xml
+
+-------------------
+<project>
+ ...
+ <build>
+ ...
+ <plugins>
+ <plugin>
+ <groupId>org.apache.myfaces.buildtools</groupId>
+ <artifactId>myfaces-builder-plugin</artifactId>
+ <version>1.0.2<version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build-metadata</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ ...
+ </build>
+ ...
+</project>
+-------------------
+
+ This goal scans all source classes for annotations or doclets and other metadata
+ files inside the project dependences and build the metadata file
+ (META-INF/myfaces-metadata.xml), required by other goals to work.
+
+Archetype using myfaces-builder-plugin
+
+ The latest myfaces-archetype-jsfcomponents available {{{http://svn.apache.org/repos/asf/myfaces/myfaces-build-tools/trunk/maven2-archetypes/myfaces-archetype-jsfcomponents/}here}}
+ or with version 1.0.2 or upper uses myfaces-builder-plugin to generate component classes,
+ tag classes, config files, etc. Just checkout the code, compile it and look the instructions on
+ {{{http://wiki.apache.org/myfaces/MyFaces_Archetypes_for_Maven}Myfaces Archetypes for Maven}}.
+
+Generate custom components
+
+ The code below shows how to configure the plugin to generate metadata
+ and then use it to generate component classes.
+
+-------------------
+<project>
+ ...
+ <build>
+ ...
+ <plugins>
+ <plugin>
+ <groupId>org.apache.myfaces.buildtools</groupId>
+ <artifactId>myfaces-builder-plugin</artifactId>
+ <version>1.0.2<version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build-metadata</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>makecomp</id>
+ <goals>
+ <goal>make-components</goal>
+ </goals>
+ <configuration>
+ <jsfVersion>12</jsfVersion>
+ <templateComponentName>myComponentTemplateClass.vm</templateComponentName>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ ...
+ </build>
+ ...
+</project>
+-------------------
+
+ Take a look at user guide section to see more detailed information.
\ No newline at end of file
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/apt/properties.apt b/myfaces-builder-plugin/src/site/apt/properties.apt
new file mode 100644
index 0000000..02cb91c
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/properties.apt
@@ -0,0 +1,146 @@
+ ~~ 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.
+
+ ------
+ Properties
+ ------
+
+Properties
+
+ Components, converters and validators have properties. Usually,
+ properties must be defined on .tld files. Also, property getter/setter
+ and saveState/restoreState methods can be generated automatically,
+ reducing the amount of code that should be maintained.
+
+ Properties are inherited, so if a component/converter/validator extends
+ from a parent component/converter/validator that has some property
+ defined, the child must have it on its .tld.
+
+ But sometimes we have the following scenarios:
+
+ * Components, converters and validators also have properties with
+ no getter and setters (like "binding" property), which are implemented
+ in their tag classes or facelets tag handler.
+
+ * Also, some properties implemented on a parent class are not
+ implemented on some children, so we need to exclude it from its
+ tld definition.
+
+ * Users can implement its own setter and getter methods for properties.
+
+ * Some properties are related only to component but should not be on
+ tld.
+
+ * Some properties have some specific behavior (for example they could
+ contains objects implementing StateHolder interface).
+
+ All these cases could be handled using @JSFProperty and @JSFJspProperty
+ annotations. Below there are some examples describing how to use it.
+
+* General case
+
+ The most common case is let the property body be generated.
+
+-------------------
+
+ @JSFProperty
+ public abstract String getAutocomplete();
+
+-------------------
+
+* Custom Implementation of getter/setters
+
+ One example is UIViewRoot "renderKitId" property:
+
+-------------------
+ @JSFProperty
+ public String getRenderKitId()
+ {
+ //... custom implementation ...
+ }
+
+ public void setRenderKitId(String renderKitId)
+ {
+ //... custom implementation ...
+ }
+-------------------
+
+* Properties without getter/setters
+
+ This syntax should be used only in very special cases and users should
+ use @JSFProperty annotation/doclet instead.
+
+-------------------
+@JSFComponent(type = "javax.faces.ComponentBase", family = "javax.faces.ComponentBase", desc = "base component when all components must inherit", tagClass = "javax.faces.webapp.UIComponentELTag", configExcluded = true)
+@JSFJspProperty(name = "binding",
+ returnType = "javax.faces.component.UIComponent",
+ longDesc = "Identifies a backing bean property (of type UIComponent or appropriate subclass) to bind to this component instance. This value must be an EL expression.", desc = "backing bean property to bind to this component instance")
+public abstract class UIComponentBase extends UIComponent
+{
+ // .... some code ...
+}
+-------------------
+
+* Excluding properties from tld
+
+ One example is UIParameter "rendered" property:
+
+-------------------
+
+ /**
+ * Disable this property; although this class extends a base-class that defines a read/write rendered property, this
+ * particular subclass does not support setting it. Yes, this is broken OO design: direct all complaints to the JSF
+ * spec group.
+ */
+ @Override
+ @JSFProperty(tagExcluded = true)
+ public void setRendered(boolean state)
+ {
+ super.setRendered(state);
+ // call parent method due TCK problems
+ // throw new UnsupportedOperationException();
+ }
+-------------------
+
+* Properties with different name in component and tag class
+
+ One example is UICommand "action" property. To change it on tld,
+ use "jspName".
+
+-------------------
+ @JSFProperty(stateHolder = true, returnSignature = "java.lang.Object", jspName = "action")
+ public MethodExpression getActionExpression()
+ {
+ // .... some code ...
+ }
+-------------------
+
+* MethodExpression/MethodBinding properties
+
+-------------------
+
+ @JSFProperty(stateHolder = true, returnSignature = "void", methodSignature = "javax.faces.event.ActionEvent")
+ public MethodBinding getActionListener()
+ {
+ // .... some code ...
+ }
+
+ @JSFProperty(stateHolder = true, returnSignature = "java.lang.Object", jspName = "action")
+ public MethodExpression getActionExpression()
+ {
+ // .... some code ...
+ }
+-------------------
+
diff --git a/myfaces-builder-plugin/src/site/apt/setup.apt b/myfaces-builder-plugin/src/site/apt/setup.apt
new file mode 100644
index 0000000..e7c3255
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/setup.apt
@@ -0,0 +1,168 @@
+ ~~ 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.
+
+ ------
+ Setting up your project
+ ------
+
+Setting up your project
+
+* Configuring your pom.xml
+
+ According to your jsf version you will need to set the required
+ dependencies.
+
+ In jsf 1.1 (use doclets).
+
+------------------------------------------------------
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>1.1.6</version>
+ <scope>provided</scope>
+ </dependency>
+------------------------------------------------------
+
+ In jsf 1.2 (use annotations).
+
+------------------------------------------------------
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>1.2.6</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.myfaces.buildtools</groupId>
+ <artifactId>myfaces-builder-annotations</artifactId>
+ <version>1.0.2</version>
+ <scope>provided</scope>
+ </dependency>
+------------------------------------------------------
+
+ If you are working with converters and validators, you should use
+ myfaces commons dependencies as base for it:
+
+-----------------------------------------------------------
+ <dependency>
+ <groupId>org.apache.myfaces.commons</groupId>
+ <artifactId>myfaces-validators12</artifactId>
+ <version>1.0.0</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.myfaces.commons</groupId>
+ <artifactId>myfaces-converters12</artifactId>
+ <version>1.0.0</version>
+ <scope>compile</scope>
+ </dependency>
+-----------------------------------------------------------
+
+ Then you need to define the plugin configuration in your projects
+ pom.xml like this:
+
+-------------------
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <excludes>
+ <exclude>**/*.vm</exclude>
+ </excludes>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.myfaces.buildtools</groupId>
+ <artifactId>myfaces-builder-plugin</artifactId>
+ <version>1.0.2</version>
+ <executions>
+ <execution>
+ <id>buildmetadata</id>
+ <goals>
+ <goal>build-metadata</goal>
+ <!-- when use components -->
+ <goal>make-components</goal>
+ <goal>make-tags</goal>
+
+ <!-- when use validators -->
+ <goal>make-validators</goal>
+ <goal>make-validator-tags</goal>
+
+ <!-- when use converters -->
+ <goal>make-converter-tags</goal>
+ </goals>
+ <configuration>
+ <!-- Use 1.1 or 1.2 according to your jsf version -->
+ <jsfVersion>1.2</jsfVersion>
+ </configuration>
+ </execution>
+ <execution>
+ <id>makefacesconfig</id>
+ <configuration>
+ <xmlFile>META-INF/faces-config.xml</xmlFile>
+ </configuration>
+ <goals>
+ <goal>make-config</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>maketld</id>
+ <configuration>
+ <xmlFile>META-INF/mycomponents.tld</xmlFile>
+ <!-- as templateFile you can use tomahawk.vm or tomahawk12.vm -->
+ <templateFile>mycomponents.tld.vm</templateFile>
+ <params>
+ <shortname>mycomponents</shortname>
+ <uri>http://www.myorganitzation.org/mycomponents</uri>
+ <displayname>Custom tag library.</displayname>
+ <description>Enhanced standard JSP actions and custom MyFaces actions.</description>
+ </params>
+ </configuration>
+ <goals>
+ <goal>make-config</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>makefaceletstaglib</id>
+ <configuration>
+ <xmlFile>META-INF/mycomponents.taglib.xml</xmlFile>
+ <xmlBaseFile>src/main/conf/META-INF/facelets-taglib-base.xml</xmlBaseFile>
+ <templateFile>facelets-taglib.vm</templateFile>
+ <params>
+ <shortname>mycomponents</shortname>
+ <uri>http://www.myorganitzation.org/mycomponents</uri>
+ </params>
+ </configuration>
+ <goals>
+ <goal>make-config</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+-------------------
+
+* Customizing your templates
+
+ The plugin uses velocity templates to generate files, and on its jar
+ there are some already defined. If you need some file (like a template
+ for tld) you can find the most up to date template on tomahawk core
+ or core12.
+
+ More detailed information can be found {{{templates.html}here}}.
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/site/apt/tags.apt b/myfaces-builder-plugin/src/site/apt/tags.apt
new file mode 100644
index 0000000..1e8874c
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/tags.apt
@@ -0,0 +1,82 @@
+ ~~ 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.
+
+ ------
+ Creating Custom JSF Tags
+ ------
+
+Creating Custom JSF Tags
+
+ A JSF Tag needs the following elements:
+
+ * JSP Tag class.
+
+ * Tag entry on tld.
+
+ * Facelets Tag Handler class (optional).
+
+ * Tag entry on facelets taglib (optional).
+
+ Myfaces builder plugin provide annotations/doclets to help users maintain
+ configuration files. In this way, all information for a tag is just in
+ one file.
+
+ Any tag is registered on facelets taglib if it has a related tag handler.
+ Usually, custom tag classes should have facelets tag handlers with
+ similar functions, but on facelets world there is no need to define
+ properties on a xml file.
+
+Setting up your project
+
+ All information related can be found {{{setup.html}here}}.
+
+Configuration files (faces-config.xml, .tld, facelets taglib)
+
+ This {{{config-files.html}page}} shows some examples.
+
+Annotate JSF Tag Classes
+
+ Just add the annotations/doclets as presented below:
+
+-------------------
+
+@JSFJspTag(
+ name = "f:valueChangeListener",
+ bodyContent = "empty")
+public class ValueChangeListenerTag extends
+ GenericListenerTag<EditableValueHolder, ValueChangeListener>
+{
+
+ /** ............. some code goes here ................. **/
+
+ @Override
+ @JSFJspAttribute(
+ className = "java.lang.String",
+ rtexprvalue = true)
+ public void setType(ValueExpression type)
+ {
+ super.setType(type);
+ }
+
+ @Override
+ @JSFJspAttribute(
+ className = "javax.faces.event.ValueChangeListener",
+ rtexprvalue = true)
+ public void setBinding(ValueExpression binding)
+ {
+ super.setBinding(binding);
+ }
+}
+-------------------
\ No newline at end of file
diff --git a/myfaces-builder-plugin/src/site/apt/templates.apt b/myfaces-builder-plugin/src/site/apt/templates.apt
new file mode 100644
index 0000000..eb65d91
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/templates.apt
@@ -0,0 +1,54 @@
+ ~~ 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.
+
+ ------
+ Template Files
+ ------
+
+Template Files
+
+ The plugin uses apache velocity to generate several types of files like
+ component classes, tag classes, configuration files and others.
+
+ In this way, the plugin provides flexibility, allowing users to write
+ custom templates to fit their needs.
+
+ Template examples can be found inside myfaces-builder-plugin jar file
+ on META-INF directory.
+
+ All velocity template files by default should be on
+ src/main/resource/META-INF path of your project. The plugin tries to
+ find the template first there and then on the plugin jar, so you
+ can override the base template copying it from the jar to this path.
+
+ You can find template examples in the following locations:
+
+ * myfaces core project source code.
+
+ * tomahawk
+ {{{http://svn.apache.org/repos/asf/myfaces/tomahawk/trunk/core/src/main/resources/META-INF/}core}},
+ {{{http://svn.apache.org/repos/asf/myfaces/tomahawk/trunk/core12/src/main/resources/META-INF/}core12}}
+ and sandbox
+ {{{http://svn.apache.org/repos/asf/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/META-INF/}core}},
+ {{{http://svn.apache.org/repos/asf/myfaces/tomahawk/trunk/sandbox/core12/src/main/resources/META-INF/}core12}}
+ source code.
+
+ * myfaces commons source code (
+ {{{http://svn.apache.org/repos/asf/myfaces/commons/trunk/myfaces-commons-converters/src/main/resources/META-INF/}converters}} and
+ {{{http://svn.apache.org/repos/asf/myfaces/commons/trunk/myfaces-commons-validators/src/main/resources/META-INF/}validators}} ).
+
+ As new release of builder plugin continues, new templates will be added
+ to myfaces-builder-plugin jar, but the latest ones can be found on
+ the previous locations.
diff --git a/myfaces-builder-plugin/src/site/apt/validators.apt b/myfaces-builder-plugin/src/site/apt/validators.apt
new file mode 100644
index 0000000..fab3bed
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/apt/validators.apt
@@ -0,0 +1,83 @@
+ ~~ 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.
+
+ ------
+ Creating Custom Validators
+ ------
+
+Creating Custom Validators
+
+ A JSF Validator needs the following elements:
+
+ * A class implementing validator interface.
+
+ * Entry on faces-config.xml.
+
+ * Tag entry on tld.
+
+ * Tag entry on facelets taglib (optional).
+
+ * JSP Tag class
+
+ Myfaces builder plugin provide annotations/doclets to help users maintain
+ configuration files, and generating both validator classes and
+ validator jsp tag classes automatically. In this way, all information
+ for a validator is just in one file (the class implementing
+ Validator interface).
+
+ For both jsf versions 1.1 and 1.2, it is necessary to provide
+ base classes for validators and tag classes, where all generated should
+ inherit. This class is on myfaces commons validators project, but
+ users can provide custom templates implementations for it.
+
+ It is possible to use abstract pattern for create validator classes,
+ in similar way to components.
+
+Setting up your project
+
+ All information related can be found {{{setup.html}here}}.
+
+Configuration files (faces-config.xml, .tld, facelets taglib)
+
+ This {{{config-files.html}page}} shows some examples.
+
+Annotate Validator Classes
+
+ Just add the annotations/doclets as presented below:
+
+-------------------
+ @JSFValidator(
+ name = "mcv:validateEmail",
+ tagClass = "org.apache.myfaces.commons.validator.ValidateEmailTag")
+public class EmailValidator extends org.apache.myfaces.commons.validator.ValidatorBase
+{
+
+ public static final String VALIDATOR_ID = "org.apache.myfaces.commons.validator.Email";
+
+ /** .......... impl code goes here ......... **/
+
+ @JSFProperty
+ public String getProperty()
+ {
+ //Some stuff
+ }
+}
+-------------------
+
+Write a Validator Class using Abstract Pattern
+
+ See {{{http://myfaces.apache.org/commons/index.html}myfaces commons}}
+ validators project for examples.
+
diff --git a/myfaces-builder-plugin/src/site/site.xml b/myfaces-builder-plugin/src/site/site.xml
new file mode 100644
index 0000000..d679121
--- /dev/null
+++ b/myfaces-builder-plugin/src/site/site.xml
@@ -0,0 +1,73 @@
+<?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="Goals" href="plugin-info.html"/>
+ <item name="How to Use" href="howto.html"/>
+ <item name="Plugin Javadoc" href="apidocs/index.html"/>
+ <item name="Doclets and Annotations" href="doclets-annotations.html"/>
+ <item name="Annotations Javadoc" href="http://myfaces.apache.org/build-tools/plugins/myfaces-builder-annotations/apidocs/index.html"/>
+ <item name="Wiki" href="http://wiki.apache.org/myfaces/MyfacesBuilderPlugin"/>
+ </menu>
+
+ <menu name="Users Guide">
+ <item name="Setting up your project" href="setup.html"/>
+ <item name="Template Files" href="templates.html"/>
+ <item name="Configuration Files" href="config-files.html"/>
+ <item name="Components" href="components.html"/>
+ <item name="Converters" href="converters.html"/>
+ <item name="Validators" href="validators.html"/>
+ <item name="Properties for Components, Converters and Validators" href="properties.html"/>
+ <item name="JSP Tags" href="tags.html"/>
+ <item name="Attributes for JSP Tags" href="attributes.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>