You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2008/06/21 21:46:06 UTC

svn commit: r670250 - in /myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder: BuildMetaDataMojo.java IOUtils.java

Author: skitching
Date: Sat Jun 21 12:46:05 2008
New Revision: 670250

URL: http://svn.apache.org/viewvc?rev=670250&view=rev
Log:
* add documentation
* simplify handling of dependencyModelIds; just load them all and discard some later.
  This removes duplicated code in the IOUtils class.

Modified:
    myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java
    myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java

Modified: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java
URL: http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java?rev=670250&r1=670249&r2=670250&view=diff
==============================================================================
--- myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java (original)
+++ myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/BuildMetaDataMojo.java Sat Jun 21 12:46:05 2008
@@ -26,8 +26,6 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.maven.model.Resource;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -44,6 +42,15 @@
  * xml file for use by other goals of this plugin.
  * <p>
  * By default, the generated file is named "META-INF/myfaces-metadata.xml".
+ * This file will be included in the final artifact for this project. Having
+ * that metadata file embedded in the generated jarfile is useful for two
+ * purposes:
+ * <ul>
+ * <li>It is needed if other projects then use the maven-builder-plugin to
+ * create subclasses of the jsf classes in this project.
+ * <li>It is good documentation (more precise than the tld and faces-config.xml
+ * files).
+ * </ul>
  * <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
@@ -58,8 +65,6 @@
  */
 public class BuildMetaDataMojo extends AbstractMojo
 {
-    final Log log = LogFactory.getLog(BuildMetaDataMojo.class.getName());
-
     /**
      * Injected Maven project object.
      * 
@@ -69,27 +74,58 @@
     private MavenProject project;
 
     /**
-     * Injected build directory for all generated stuff.
+     * 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. 
      * 
-     * @parameter expression="${project.build.directory}/maven-faces-plugin/main/resources"
+     * @parameter expression="${project.build.directory}/myfaces-builder-plugin/main/resources"
      */
     private File targetDirectory;
 
     /**
-     * Injected name of file to generate, relative to 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>
+     * 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
+     * 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>
+     * 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>
+     * 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.
      * 
      * @parameter
      */
@@ -97,76 +133,124 @@
 
     /**
      * Replace the package prefix
+     * <p>
+     * See replacePackagePrefixTagTo.
      * 
      * @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>
+     * 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>
+     * 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>
+     * This property is only needed in rare situations; normally it can be omitted.
      * 
      * @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>
+     * Note that by default, a project's modelId is the same as the artifactId.
+     * 
      * @parameter
      */
     private List dependencyModelIds;
     
     /**
-     * Alternate file to read model definition and merge it to the
-     * current model, usually used when it is necessary to avoid dependencies.
-     * 
-     * One example is when it is necessary a release of the library (tomahawk for 
-     * example), but the previous version of the scanned dependency library
-     * (myfaces-api) does not have META-INF/myfaces-metadata.xml in his jar,
-     * so when the metadata is generated the result is a lot of errors due to 
-     * the model is incomplete.
-     * 
-     * Other use is when it is necessary to add some custom model definitions to
-     * the model to be built, but this should be avoided. Instead, this goal should
-     * be used on the dependency library, release the dependency library and
-     * then the library that consume the metadata.  
+     * 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>
+     * The specified filename is relative to the current working directory.
+     * <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> 
+     * 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>
+     * 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!
      * 
      * @parameter
      */
     private File inputFile;
     
     /**
-     * Execute the Mojo.
+     * 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 {
+        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){
+        }
+        catch(IOException e)
+        {
             throw new MojoExecutionException("Error during generation", e);
         }
         
+        List models = IOUtils.getModelsFromArtifacts(project); 
+        models = sortModels(models);
+
         Model model = new Model();
 
-        List models = null;
-        if (dependencyModelIds != null)
-        {
-            models = IOUtils.getModelsFromArtifacts(project,dependencyModelIds);
-        }
-        else
-        {
-            models = IOUtils.getModelsFromArtifacts(project); 
-        }
-        
         if (inputFile != null)
         {
+            // An explicitly-specified input model takes precedence
             Model fileModel = IOUtils.loadModel(inputFile);
-            //The input model takes precedence
             model.merge(fileModel);
         }
         
-        models = sortModels(models);
         
-        for (Iterator it = models.iterator(); it.hasNext();){
+        for (Iterator it = models.iterator(); it.hasNext();)
+        {
             Model artifactModel = (Model) it.next();
-            model.merge(artifactModel);
+            
+            if ((dependencyModelIds == null) || dependencyModelIds.contains(artifactModel.getModelId()))
+            {
+                model.merge(artifactModel);
+            }
         }
 
         buildModel(model, project);
@@ -178,10 +262,15 @@
     }
     
     /**
-     * This function order the models as suggested by the modelIdOrder.
+     * 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
@@ -196,12 +285,14 @@
         
         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();
             
@@ -212,7 +303,9 @@
                 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;
@@ -237,7 +330,6 @@
             {
                 comp.setTagClass(StringUtils.replaceOnce(
                         comp.getTagClass(), replacePackagePrefixTagFrom, replacePackagePrefixTagTo));
-                log.info("Tag class changed to:"+comp.getTagClass());
             }
         }
     }

Modified: myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java
URL: http://svn.apache.org/viewvc/myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java?rev=670250&r1=670249&r2=670250&view=diff
==============================================================================
--- myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java (original)
+++ myfaces/myfaces-build-tools/trunk/maven2-plugins/myfaces-builder-plugin/src/main/java/org/apache/myfaces/buildtools/maven2/plugin/builder/IOUtils.java Sat Jun 21 12:46:05 2008
@@ -234,7 +234,12 @@
 
         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
     {
@@ -264,121 +269,14 @@
 
                     is = getStream(MYFACES_METADATA, archetypeJarLoader);
 
-                    if (is == null)
-                    {
-
-                        //System.out.println("Artifact: "
-                        //        + artifact.getFile().getName()
-                        //        + " does not have META-INF/myfaces-metadata.xml");
-                    }
-                    else
-                    {
-                        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;
-    }
-    
-    public static List getModelsFromArtifacts(MavenProject project,
-            List dependencyModelIds) 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)
-                    {
-
-                        //System.out.println("Artifact: "
-                        //        + artifact.getFile().getName()
-                        //        + " does not have META-INF/myfaces-metadata.xml");
-                    }
-                    else
-                    {
                         Reader r = null;
                         try
                         {
                             r = new InputStreamReader(is);
                             Model m = readModel(r);
-                            if (dependencyModelIds.contains(m.getModelId()))
-                            {
-                                models.add(m);
-                            }
+                            models.add(m);
                             r.close();
                         }
                         catch (IOException e)
@@ -431,7 +329,6 @@
         }
         return models;
     }
-    
         
     private static InputStream getStream( String name,
             ClassLoader loader )