Coverage Report - org.apache.maven.plugin.doap.DoapMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
DoapMojo
0 %
0/793
0 %
0/368
0
DoapMojo$1
0 %
0/20
0 %
0/30
0
DoapMojo$UserMessages
0 %
0/52
0 %
0/55
0
 
 1  
 package org.apache.maven.plugin.doap;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *  http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.io.Writer;
 25  
 import java.net.MalformedURLException;
 26  
 import java.net.URL;
 27  
 import java.text.DateFormat;
 28  
 import java.text.ParseException;
 29  
 import java.text.SimpleDateFormat;
 30  
 import java.util.ArrayList;
 31  
 import java.util.Arrays;
 32  
 import java.util.Collections;
 33  
 import java.util.Comparator;
 34  
 import java.util.Date;
 35  
 import java.util.List;
 36  
 import java.util.Locale;
 37  
 import java.util.Map;
 38  
 import java.util.Map.Entry;
 39  
 import java.util.Set;
 40  
 import java.util.TimeZone;
 41  
 
 42  
 import org.apache.maven.artifact.Artifact;
 43  
 import org.apache.maven.artifact.factory.ArtifactFactory;
 44  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 45  
 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
 46  
 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
 47  
 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
 48  
 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
 49  
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 50  
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
 51  
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 52  
 import org.apache.maven.model.Contributor;
 53  
 import org.apache.maven.model.Developer;
 54  
 import org.apache.maven.model.License;
 55  
 import org.apache.maven.plugin.AbstractMojo;
 56  
 import org.apache.maven.plugin.MojoExecutionException;
 57  
 import org.apache.maven.plugin.doap.options.ASFExtOptions;
 58  
 import org.apache.maven.plugin.doap.options.ASFExtOptionsUtil;
 59  
 import org.apache.maven.plugin.doap.options.DoapArtifact;
 60  
 import org.apache.maven.plugin.doap.options.DoapOptions;
 61  
 import org.apache.maven.plugin.doap.options.ExtOptions;
 62  
 import org.apache.maven.plugin.doap.options.Standard;
 63  
 import org.apache.maven.project.MavenProject;
 64  
 import org.apache.maven.project.MavenProjectBuilder;
 65  
 import org.apache.maven.project.ProjectBuildingException;
 66  
 import org.apache.maven.scm.manager.NoSuchScmProviderException;
 67  
 import org.apache.maven.scm.manager.ScmManager;
 68  
 import org.apache.maven.scm.provider.cvslib.repository.CvsScmProviderRepository;
 69  
 import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
 70  
 import org.apache.maven.scm.repository.ScmRepository;
 71  
 import org.apache.maven.scm.repository.ScmRepositoryException;
 72  
 import org.apache.maven.settings.Settings;
 73  
 import org.codehaus.plexus.i18n.I18N;
 74  
 import org.codehaus.plexus.util.FileUtils;
 75  
 import org.codehaus.plexus.util.StringUtils;
 76  
 import org.codehaus.plexus.util.WriterFactory;
 77  
 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
 78  
 import org.codehaus.plexus.util.xml.XMLWriter;
 79  
 
 80  
 /**
 81  
  * Generate a <a href="http://usefulinc.com/ns/doap">Description of a Project (DOAP)</a> file from the main information
 82  
  * found in a POM. <br/>
 83  
  * <b>Note</b>: The generated file is tailored for use by projects at <a
 84  
  * href="http://projects.apache.org/doap.html">Apache</a>.
 85  
  *
 86  
  * @author Jason van Zyl
 87  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 88  
  * @version $Id: org.apache.maven.plugin.doap.DoapMojo.html 815337 2012-05-01 21:52:10Z hboutemy $
 89  
  * @since 1.0-beta-1
 90  
  * @goal generate
 91  
  */
 92  0
 public class DoapMojo
 93  
     extends AbstractMojo
 94  
 {
 95  
     /** UTC Time Zone */
 96  0
     private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
 97  
 
 98  
     /** Date format for <lastUpdated/> tag in the repository metadata, i.e.: yyyyMMddHHmmss */
 99  
     private static final DateFormat REPOSITORY_DATE_FORMAT;
 100  
 
 101  
     /** Date format for DOAP file, i.e. ISO-8601 YYYY-MM-DD */
 102  
     private static final DateFormat DOAP_DATE_FORMAT;
 103  
 
 104  
     static
 105  
     {
 106  0
         REPOSITORY_DATE_FORMAT = new SimpleDateFormat( "yyyyMMddHHmmss", Locale.ENGLISH );
 107  0
         REPOSITORY_DATE_FORMAT.setTimeZone( UTC_TIME_ZONE );
 108  
 
 109  0
         DOAP_DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd", Locale.ENGLISH );
 110  0
         DOAP_DATE_FORMAT.setTimeZone( UTC_TIME_ZONE );
 111  0
     }
 112  
 
 113  
     // ----------------------------------------------------------------------
 114  
     // Mojo components
 115  
     // ----------------------------------------------------------------------
 116  
 
 117  
     /**
 118  
      * Maven SCM Manager.
 119  
      *
 120  
      * @component
 121  
      * @since 1.0
 122  
      */
 123  
     private ScmManager scmManager;
 124  
 
 125  
     /**
 126  
      * Artifact factory.
 127  
      *
 128  
      * @component
 129  
      * @since 1.0
 130  
      */
 131  
     private ArtifactFactory artifactFactory;
 132  
 
 133  
     /**
 134  
      * Used to resolve artifacts.
 135  
      *
 136  
      * @component
 137  
      * @since 1.0
 138  
      */
 139  
     private RepositoryMetadataManager repositoryMetadataManager;
 140  
 
 141  
     /**
 142  
      * Internationalization component.
 143  
      *
 144  
      * @component
 145  
      * @since 1.0
 146  
      */
 147  
     private I18N i18n;
 148  
 
 149  
     // ----------------------------------------------------------------------
 150  
     // Mojo parameters
 151  
     // ----------------------------------------------------------------------
 152  
 
 153  
     /**
 154  
      * The POM from which information will be extracted to create a DOAP file.
 155  
      *
 156  
      * @parameter default-value="${project}"
 157  
      * @readonly
 158  
      * @required
 159  
      */
 160  
     private MavenProject project;
 161  
 
 162  
     /**
 163  
      * The name of the DOAP file that will be generated.
 164  
      *
 165  
      * @parameter expression="${doapFile}" default-value="doap_${project.artifactId}.rdf"
 166  
      * @required
 167  
      */
 168  
     private String doapFile;
 169  
 
 170  
     /**
 171  
      * The output directory of the DOAP file that will be generated.
 172  
      *
 173  
      * @parameter default-value="${project.reporting.outputDirectory}"
 174  
      * @required
 175  
      * @since 1.1
 176  
      */
 177  
     private String outputDirectory;
 178  
 
 179  
     /**
 180  
      * The local repository where the artifacts are located.
 181  
      *
 182  
      * @parameter default-value="${localRepository}"
 183  
      * @required
 184  
      * @readonly
 185  
      * @since 1.0
 186  
      */
 187  
     private ArtifactRepository localRepository;
 188  
 
 189  
     /**
 190  
      * The remote repositories where the artifacts are located.
 191  
      *
 192  
      * @parameter default-value="${project.remoteArtifactRepositories}"
 193  
      * @required
 194  
      * @readonly
 195  
      * @since 1.0
 196  
      */
 197  
     private List<ArtifactRepository> remoteRepositories;
 198  
 
 199  
     /**
 200  
      * Factory for creating artifact objects
 201  
      *
 202  
      * @component
 203  
      * @since 1.1
 204  
      */
 205  
     private ArtifactFactory factory;
 206  
 
 207  
     /**
 208  
      * Project builder
 209  
      *
 210  
      * @component
 211  
      * @since 1.1
 212  
      */
 213  
     private MavenProjectBuilder mavenProjectBuilder;
 214  
 
 215  
     /**
 216  
      * Used for resolving artifacts
 217  
      *
 218  
      * @component
 219  
      * @since 1.1
 220  
      */
 221  
     private ArtifactResolver resolver;
 222  
 
 223  
     /**
 224  
      * The current user system settings for use in Maven.
 225  
      *
 226  
      * @parameter expression="${settings}"
 227  
      * @required
 228  
      * @readonly
 229  
      * @since 1.1
 230  
      */
 231  
     protected Settings settings;
 232  
 
 233  
     // ----------------------------------------------------------------------
 234  
     // Doap options
 235  
     // ----------------------------------------------------------------------
 236  
 
 237  
     /**
 238  
      * The category which should be displayed in the DOAP file.
 239  
      *
 240  
      * @parameter expression="${category}"
 241  
      * @deprecated Since 1.0. Instead of, configure
 242  
      *             <code>&lt;doapOptions&gt;&lt;category/&gt;&lt;/doapOptions&gt;</code> parameter.
 243  
      */
 244  
     private String category;
 245  
 
 246  
     /**
 247  
      * The programming language which should be displayed in the DOAP file.
 248  
      *
 249  
      * @parameter expression="${language}"
 250  
      * @deprecated Since 1.0. Instead of, configure
 251  
      *             <code>&lt;doapOptions&gt;&lt;programmingLanguage/&gt;&lt;/doapOptions&gt;</code> parameter.
 252  
      */
 253  
     private String language;
 254  
 
 255  
     /**
 256  
      * Specific DOAP parameters, i.e. options that POM doesn't have any notions. <br/>
 257  
      * Example:
 258  
      *
 259  
      * <pre>
 260  
      * &lt;doapOptions&gt;
 261  
      * &nbsp;&nbsp;&lt;programmingLanguage&gt;java&lt;/programmingLanguage&gt;
 262  
      * &lt;/doapOptions&gt;
 263  
      * </pre>
 264  
      *
 265  
      * <br/>
 266  
      * See <a href="./apidocs/org/apache/maven/plugin/doap/options/DoapOptions.html">Javadoc</a> <br/>
 267  
      *
 268  
      * @parameter expression="${doapOptions}"
 269  
      * @since 1.0
 270  
      * @see <a href="http://usefulinc.com/ns/doap#">http://usefulinc.com/ns/doap#</a>
 271  
      */
 272  
     private DoapOptions doapOptions;
 273  
 
 274  
     /**
 275  
      * Specific ASF extensions parameters, i.e. options that POM doesn't have any notions but required by ASF DOAP
 276  
      * requirements. <br/>
 277  
      * Example:
 278  
      *
 279  
      * <pre>
 280  
      * &lt;asfExtOptions&gt;
 281  
      * &nbsp;&nbsp;&lt;included&gt;true&lt;/included&gt;
 282  
      * &nbsp;&nbsp;&lt;charter&gt;The mission of the Apache XXX project is to create and maintain software
 283  
      * &nbsp;&nbsp;libraries that provide ...&lt;/charter&gt;
 284  
      * &nbsp;&nbsp;...
 285  
      * &lt;/asfExtOptions&gt;
 286  
      * </pre>
 287  
      *
 288  
      * <b>Note</b>: By default, <code>&lt;asfExtOptions&gt;&lt;included/&gt;&lt;/asfExtOptions&gt;</code> will be
 289  
      * automatically set to <code>true</code> if the project is hosted at ASF. <br/>
 290  
      * See <a href="./apidocs/org/apache/maven/plugin/doap/options/ASFExtOptions.html">Javadoc</a> <br/>
 291  
      *
 292  
      * @parameter expression="${asfExtOptions}"
 293  
      * @since 1.0
 294  
      * @see <a href="http://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/asfext">
 295  
      *      http://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/asfext</a>
 296  
      * @see <a href="http://projects.apache.org/docs/pmc.html">http://projects.apache.org/docs/pmc.html</a>
 297  
      * @see <a href="http://projects.apache.org/docs/standards.html">http://projects.apache.org/docs/standards.html</a>
 298  
      * @see ASFExtOptionsUtil#isASFProject(MavenProject)
 299  
      */
 300  
     private ASFExtOptions asfExtOptions;
 301  
 
 302  
     /**
 303  
      * The value for the <code>xml:lang</code> attribute used by the <code>&lt;rdf:RDF/&gt;<code>,
 304  
      * <code>&lt;description/&gt;</code> and <code>&lt;shortdesc/&gt;</code> elements. <br/>
 305  
      * POM doesn't have any notions about language. <br/>
 306  
      * See <a href="http://www.w3.org/TR/REC-xml/#sec-lang-tag">http://www.w3.org/TR/REC-xml/#sec-lang-tag</a> <br/>
 307  
      *
 308  
      * @parameter expression="${lang}" default-value="en"
 309  
      * @required
 310  
      * @since 1.0
 311  
      */
 312  
     private String lang;
 313  
 
 314  
     /**
 315  
      * The <code>about</code> URI-reference which should be displayed in the DOAP file. Example:
 316  
      *
 317  
      * <pre>
 318  
      * &lt;rdf:RDF&gt;
 319  
      * &nbsp;&nbsp;&lt;Project rdf:about="http://maven.apache.org/"&gt;
 320  
      * &nbsp;&nbsp;...
 321  
      * &nbsp;&nbsp;&lt;/Project&gt;
 322  
      * &lt;/rdf:RDF&gt;
 323  
      * </pre>
 324  
      *
 325  
      * See <a href="http://www.w3.org/TR/1999/REC-rdf-syntax-19990222/#aboutAttr">
 326  
      * http://www.w3.org/TR/1999/REC-rdf-syntax-19990222/#aboutAttr</a> <br/>
 327  
      *
 328  
      * @parameter expression="${about}" default-value="${project.url}"
 329  
      * @since 1.0
 330  
      */
 331  
     private String about;
 332  
 
 333  
     /**
 334  
      * Flag to validate the generated DOAP.
 335  
      *
 336  
      * @parameter default-value="true"
 337  
      * @since 1.1
 338  
      */
 339  
     private boolean validate;
 340  
 
 341  
     /**
 342  
      * An artifact to generate the DOAP file against. <br/>
 343  
      * Example:
 344  
      *
 345  
      * <pre>
 346  
      * &lt;artifact&gt;
 347  
      * &nbsp;&nbsp;&lt;groupId&gt;given-artifact-groupId&lt;/groupId&gt;
 348  
      * &nbsp;&nbsp;&lt;artifactId&gt;given-artifact-artifactId&lt;/artifactId&gt;
 349  
      * &nbsp;&nbsp;&lt;version&gt;given-artifact-version&lt;/version&gt;
 350  
      * &lt;/artifact&gt;
 351  
      * </pre>
 352  
      *
 353  
      * <br/>
 354  
      * See <a href="./apidocs/org/apache/maven/plugin/doap/options/DaopArtifact.html">Javadoc</a> <br/>
 355  
      *
 356  
      * @parameter
 357  
      * @since 1.1
 358  
      */
 359  
     private DoapArtifact artifact;
 360  
 
 361  
     /**
 362  
      * Specifies whether the DOAP generation should be skipped.
 363  
      *
 364  
      * @parameter expression="${maven.doap.skip}" default-value="false"
 365  
      * @since 1.1
 366  
      */
 367  
     private boolean skip;
 368  
 
 369  
     /**
 370  
      * Extensions parameters. <br/>
 371  
      * Example:
 372  
      *
 373  
      * <pre>
 374  
      * &lt;extOptions&gt;
 375  
      * &nbsp;&lt;extOption&gt;
 376  
      * &nbsp;&nbsp;&nbsp;&lt;xmlnsPrefix&gt;labs&lt;/xmlnsPrefix&gt;
 377  
      * &nbsp;&nbsp;&nbsp;&lt;xmlnsNamespaceURI&gt;http://labs.apache.org/doap-ext/1.0#&lt;/xmlnsNamespaceURI&gt;
 378  
      * &nbsp;&nbsp;&nbsp;&lt;extensions&gt;
 379  
      * &nbsp;&nbsp;&nbsp;&nbsp;&lt;status&gt;active&lt;/status&gt;
 380  
      * &nbsp;&nbsp;&nbsp;&lt;/extensions&gt;
 381  
      * &nbsp;&lt;/extOption&gt;
 382  
      * &lt;/extOptions&gt;
 383  
      * </pre>
 384  
      *
 385  
      * See <a href="./apidocs/org/apache/maven/plugin/doap/options/ExtOptions.html">Javadoc</a> <br/>
 386  
      *
 387  
      * @parameter expression="${extOptions}"
 388  
      * @since 1.1
 389  
      */
 390  
     private ExtOptions[] extOptions;
 391  
 
 392  
     /**
 393  
      * All warn/error messages for the user.
 394  
      *
 395  
      * @since 1.1
 396  
      */
 397  0
     private UserMessages messages = new UserMessages();
 398  
 
 399  
     // ----------------------------------------------------------------------
 400  
     // Public methods
 401  
     // ----------------------------------------------------------------------
 402  
 
 403  
     /** {@inheritDoc} */
 404  
     public void execute()
 405  
         throws MojoExecutionException
 406  
     {
 407  0
         if ( skip )
 408  
         {
 409  0
             getLog().info( "Skipping DOAP generation" );
 410  0
             return;
 411  
         }
 412  
 
 413  
         // single artifact
 414  0
         if ( artifact != null )
 415  
         {
 416  0
             MavenProject givenProject = getMavenProject( artifact );
 417  0
             if ( givenProject != null )
 418  
             {
 419  0
                 File outDir = new File( outputDirectory );
 420  0
                 if ( !outDir.isAbsolute() )
 421  
                 {
 422  0
                     outDir = new File( project.getBasedir(), outputDirectory );
 423  
                 }
 424  0
                 File outFile = new File( outDir, artifact.getDoapFileName() );
 425  0
                 writeDoapFile( givenProject, outFile );
 426  0
                 return;
 427  
             }
 428  
         }
 429  
 
 430  
         // current project
 431  0
         File outFile = new File( doapFile );
 432  0
         if ( !outFile.isAbsolute() )
 433  
         {
 434  0
             outFile = new File( project.getBasedir(), doapFile );
 435  
         }
 436  0
         if ( !doapFile.replaceAll( "\\\\", "/" ).contains( "/" ) )
 437  
         {
 438  0
             File outDir = new File( outputDirectory );
 439  0
             if ( !outDir.isAbsolute() )
 440  
             {
 441  0
                 outDir = new File( project.getBasedir(), outputDirectory );
 442  
             }
 443  0
             outFile = new File( outDir, doapFile );
 444  
         }
 445  0
         writeDoapFile( project, outFile );
 446  0
     }
 447  
 
 448  
     // ----------------------------------------------------------------------
 449  
     // Private methods
 450  
     // ----------------------------------------------------------------------
 451  
 
 452  
     /**
 453  
      * @param artifact not null
 454  
      * @return the maven project for the given doap artifact
 455  
      * @since 1.1
 456  
      */
 457  
     private MavenProject getMavenProject( DoapArtifact artifact )
 458  
     {
 459  0
         if ( artifact == null )
 460  
         {
 461  0
             return null;
 462  
         }
 463  
 
 464  0
         if ( StringUtils.isEmpty( artifact.getGroupId() ) || StringUtils.isEmpty( artifact.getArtifactId() )
 465  
             || StringUtils.isEmpty( artifact.getVersion() ) )
 466  
         {
 467  0
             getLog().warn( "Missing groupId or artifactId or version in <artifact/> parameter, ignored it." );
 468  0
             return null;
 469  
         }
 470  
 
 471  0
         getLog().info( "Using artifact " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":"
 472  
                            + artifact.getVersion() );
 473  
 
 474  
         try
 475  
         {
 476  0
             Artifact art =
 477  
                 factory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(),
 478  
                                                Artifact.SCOPE_COMPILE );
 479  
 
 480  0
             if ( art.getFile() == null )
 481  
             {
 482  0
                 MavenProject proj = mavenProjectBuilder.buildFromRepository( art, remoteRepositories, localRepository );
 483  0
                 art = proj.getArtifact();
 484  
 
 485  0
                 resolver.resolve( art, remoteRepositories, localRepository );
 486  
 
 487  0
                 return proj;
 488  
             }
 489  
         }
 490  0
         catch ( ArtifactResolutionException e )
 491  
         {
 492  0
             getLog().error( "ArtifactResolutionException: " + e.getMessage() + "\nIgnored <artifact/> parameter." );
 493  
         }
 494  0
         catch ( ArtifactNotFoundException e )
 495  
         {
 496  0
             getLog().error( "ArtifactNotFoundException: " + e.getMessage() + "\nIgnored <artifact/> parameter." );
 497  
         }
 498  0
         catch ( ProjectBuildingException e )
 499  
         {
 500  0
             getLog().error( "ProjectBuildingException: " + e.getMessage() + "\nIgnored <artifact/> parameter." );
 501  0
         }
 502  
 
 503  0
         return null;
 504  
     }
 505  
 
 506  
     /**
 507  
      * Write a doap file for the given project.
 508  
      *
 509  
      * @param project not null
 510  
      * @param outputFile not null
 511  
      * @since 1.1
 512  
      */
 513  
     private void writeDoapFile( MavenProject project, File outputFile )
 514  
         throws MojoExecutionException
 515  
     {
 516  
         // ----------------------------------------------------------------------------
 517  
         // Includes ASF extensions
 518  
         // ----------------------------------------------------------------------------
 519  
 
 520  0
         if ( !asfExtOptions.isIncluded() && ASFExtOptionsUtil.isASFProject( project ) )
 521  
         {
 522  0
             getLog().info( "This project is an ASF project, ASF Extensions to DOAP will be added." );
 523  0
             asfExtOptions.setIncluded( true );
 524  
         }
 525  
 
 526  
         // ----------------------------------------------------------------------------
 527  
         // setup pretty print xml writer
 528  
         // ----------------------------------------------------------------------------
 529  
 
 530  
         Writer w;
 531  
         try
 532  
         {
 533  0
             if ( !outputFile.getParentFile().exists() )
 534  
             {
 535  0
                 FileUtils.mkdir( outputFile.getParentFile().getAbsolutePath() );
 536  
             }
 537  
 
 538  0
             w = WriterFactory.newXmlWriter( outputFile );
 539  
         }
 540  0
         catch ( IOException e )
 541  
         {
 542  0
             throw new MojoExecutionException( "Error creating DOAP file " + outputFile.getAbsolutePath(), e );
 543  0
         }
 544  
 
 545  0
         if ( asfExtOptions.isIncluded() )
 546  
         {
 547  0
             getLog().info( "Generating an ASF DOAP file " + outputFile.getAbsolutePath() );
 548  
         }
 549  
         else
 550  
         {
 551  0
             getLog().info( "Generating a pure DOAP file " + outputFile.getAbsolutePath() );
 552  
         }
 553  
 
 554  0
         XMLWriter writer = new PrettyPrintXMLWriter( w, project.getModel().getModelEncoding(), null );
 555  
 
 556  
         // ----------------------------------------------------------------------------
 557  
         // Convert POM to DOAP
 558  
         // ----------------------------------------------------------------------------
 559  
 
 560  0
         DoapUtil.writeHeader( writer );
 561  
 
 562  
         // Heading
 563  0
         DoapUtil.writeStartElement( writer, "rdf", "RDF" );
 564  0
         if ( Arrays.binarySearch( Locale.getISOLanguages(), lang ) < 0 )
 565  
         {
 566  0
             messages.addMessage( new String[] { "doapOptions", "lang" }, lang, UserMessages.INVALID_ISO_DATE );
 567  0
             throw new MojoExecutionException( messages.getErrorMessages().get( 0 ) );
 568  
         }
 569  0
         writer.addAttribute( "xml:lang", lang );
 570  0
         if ( StringUtils.isEmpty( doapOptions.getXmlnsNamespaceURI() ) )
 571  
         {
 572  0
             messages.addMessage( new String[] { "doapOptions", "xmlnsNamespaceURI" }, null, UserMessages.REQUIRED );
 573  0
             throw new MojoExecutionException( messages.getErrorMessages().get( 0 ) );
 574  
         }
 575  0
         writer.addAttribute( "xmlns"
 576  
                                  + ( StringUtils.isEmpty( doapOptions.getXmlnsPrefix() ) ? "" : ":"
 577  
                                      + doapOptions.getXmlnsPrefix() ), doapOptions.getXmlnsNamespaceURI() );
 578  0
         writer.addAttribute( "xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#" );
 579  0
         writer.addAttribute( "xmlns:foaf", "http://xmlns.com/foaf/0.1/" );
 580  0
         if ( asfExtOptions.isIncluded() )
 581  
         {
 582  0
             if ( StringUtils.isEmpty( asfExtOptions.getXmlnsPrefix() ) )
 583  
             {
 584  0
                 messages.addMessage( new String[] { "doapOptions", "xmlnsPrefix" }, null, UserMessages.REQUIRED );
 585  0
                 throw new MojoExecutionException( messages.getErrorMessages().get( 0 ) );
 586  
             }
 587  0
             if ( StringUtils.isEmpty( asfExtOptions.getXmlnsNamespaceURI() ) )
 588  
             {
 589  0
                 messages.addMessage( new String[] { "doapOptions", "xmlnsNamespaceURI" }, null, UserMessages.REQUIRED );
 590  
             }
 591  0
             writer.addAttribute( "xmlns"
 592  
                                      + ( StringUtils.isEmpty( asfExtOptions.getXmlnsPrefix() ) ? "" : ":"
 593  
                                          + asfExtOptions.getXmlnsPrefix() ), asfExtOptions.getXmlnsNamespaceURI() );
 594  
         }
 595  0
         if ( extOptions != null && extOptions.length > 0 && !extOptions[0].getExtensions().isEmpty() )
 596  
         {
 597  0
             for ( ExtOptions extOption : extOptions )
 598  
             {
 599  0
                 if ( StringUtils.isEmpty( extOption.getXmlnsPrefix() ) )
 600  
                 {
 601  0
                     messages.addMessage( new String[] { "extOptions", "extOption", "xmlnsPrefix" }, null,
 602  
                                          UserMessages.REQUIRED );
 603  0
                     throw new MojoExecutionException( messages.getErrorMessages().get( 0 ) );
 604  
                 }
 605  0
                 if ( StringUtils.isEmpty( extOption.getXmlnsNamespaceURI() ) )
 606  
                 {
 607  0
                     messages.addMessage( new String[] { "extOptions", "extOption", "xmlnsNamespaceURI" }, null,
 608  
                                          UserMessages.REQUIRED );
 609  0
                     throw new MojoExecutionException( messages.getErrorMessages().get( 0 ) );
 610  
                 }
 611  0
                 writer.addAttribute( "xmlns"
 612  
                                          + ( StringUtils.isEmpty( extOption.getXmlnsPrefix() ) ? "" : ":"
 613  
                                              + extOption.getXmlnsPrefix() ),
 614  
                                      extOption.getXmlnsNamespaceURI() );
 615  
             }
 616  
         }
 617  
 
 618  
         // Project
 619  0
         DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "Project" );
 620  0
         boolean added = false;
 621  0
         if ( artifact != null )
 622  
         {
 623  0
             String about_ = project.getUrl();
 624  
 
 625  0
             if ( StringUtils.isNotEmpty( about_ ) )
 626  
             {
 627  
                 try
 628  
                 {
 629  0
                     new URL( about_ );
 630  
 
 631  0
                     writer.addAttribute( "rdf:about", about_ );
 632  0
                     added = true;
 633  
                 }
 634  0
                 catch ( MalformedURLException e )
 635  
                 {
 636  0
                 }
 637  
             }
 638  
 
 639  0
             if ( !added )
 640  
             {
 641  0
                 messages.getWarnMessages().add( "The project's url defined from " + artifact.toConfiguration()
 642  
                                                     + " is empty or not a valid URL, using <about/> parameter." );
 643  
             }
 644  
         }
 645  
 
 646  0
         if ( !added )
 647  
         {
 648  0
             if ( StringUtils.isNotEmpty( about ) )
 649  
             {
 650  
                 try
 651  
                 {
 652  0
                     new URL( about );
 653  
 
 654  0
                     writer.addAttribute( "rdf:about", about );
 655  
                 }
 656  0
                 catch ( MalformedURLException e )
 657  
                 {
 658  0
                     messages.addMessage( new String[] { "about" }, about, UserMessages.INVALID_URL );
 659  0
                 }
 660  0
                 added = true;
 661  
             }
 662  
         }
 663  
 
 664  0
         if ( !added )
 665  
         {
 666  0
             messages.addMessage( new String[] { "about" }, null, UserMessages.RECOMMENDED );
 667  
         }
 668  
 
 669  
         // name
 670  0
         writeName( writer, project );
 671  
 
 672  
         // description
 673  0
         writeDescription( writer, project );
 674  
 
 675  
         // implements
 676  0
         writeImplements( writer );
 677  
 
 678  
         // Audience
 679  0
         writeAudience( writer );
 680  
 
 681  
         // Vendor
 682  0
         writeVendor( writer, project );
 683  
 
 684  
         // created
 685  0
         writeCreated( writer, project );
 686  
 
 687  
         // homepage and old-homepage
 688  0
         writeHomepage( writer, project );
 689  
 
 690  
         // Blog
 691  0
         writeBlog( writer );
 692  
 
 693  
         // licenses
 694  0
         writeLicenses( writer, project );
 695  
 
 696  
         // programming-language
 697  0
         writeProgrammingLanguage( writer, project );
 698  
 
 699  
         // category
 700  0
         writeCategory( writer, project );
 701  
 
 702  
         // os
 703  0
         writeOS( writer, project );
 704  
 
 705  
         // Plateform
 706  0
         writePlateform( writer );
 707  
 
 708  
         // Language
 709  0
         writeLanguage( writer );
 710  
 
 711  
         // SCM
 712  0
         writeSourceRepositories( writer, project );
 713  
 
 714  
         // bug-database
 715  0
         writeBugDatabase( writer, project );
 716  
 
 717  
         // mailing list
 718  0
         writeMailingList( writer, project );
 719  
 
 720  
         // download-page and download-mirror
 721  0
         writeDownloadPage( writer, project );
 722  
 
 723  
         // screenshots
 724  0
         writeScreenshots( writer, project );
 725  
 
 726  
         // service-endpoint
 727  0
         writeServiceEndpoint( writer );
 728  
 
 729  
         // wiki
 730  0
         writeWiki( writer, project );
 731  
 
 732  
         // Releases
 733  0
         writeReleases( writer, project );
 734  
 
 735  
         // Developers
 736  
         @SuppressWarnings( "unchecked" )
 737  0
         List<Contributor> developers = project.getDevelopers();
 738  0
         writeContributors( writer, developers );
 739  
 
 740  
         // Contributors
 741  
         @SuppressWarnings( "unchecked" )
 742  0
         List<Contributor> contributors = project.getContributors();
 743  0
         writeContributors( writer, contributors );
 744  
 
 745  
         // Extra DOAP
 746  
         @SuppressWarnings( "unchecked" )
 747  0
         Map<String, String> map = doapOptions.getExtra();
 748  0
         writeExtra( writer, project, "Extra DOAP vocabulary.", map, doapOptions.getXmlnsPrefix() );
 749  
 
 750  
         // ASFext
 751  0
         writeASFext( writer, project );
 752  
 
 753  
         // Extra extensions
 754  0
         writeExtensions( writer );
 755  
 
 756  0
         writer.endElement(); // Project
 757  
 
 758  0
         writeOrganizations( writer );
 759  
 
 760  0
         writer.endElement(); // rdf:RDF
 761  
 
 762  
         try
 763  
         {
 764  0
             w.close();
 765  
         }
 766  0
         catch ( IOException e )
 767  
         {
 768  0
             throw new MojoExecutionException( "Error when closing the writer.", e );
 769  0
         }
 770  
 
 771  0
         if ( !messages.getWarnMessages().isEmpty() )
 772  
         {
 773  0
             for ( String warn : messages.getWarnMessages() )
 774  
             {
 775  0
                 getLog().warn( warn );
 776  
             }
 777  
         }
 778  
 
 779  0
         if ( !messages.getErrorMessages().isEmpty() )
 780  
         {
 781  0
             getLog().error( "" );
 782  0
             for ( String error : messages.getErrorMessages() )
 783  
             {
 784  0
                 getLog().error( error );
 785  
             }
 786  0
             getLog().error( "" );
 787  
 
 788  0
             if ( ASFExtOptionsUtil.isASFProject( project ) )
 789  
             {
 790  0
                 getLog().error( "For more information about the errors and possible solutions, please read the plugin documentation:" );
 791  0
                 getLog().error( "http://maven.apache.org/plugins/maven-doap-plugin/usage.html#DOAP_ASF_Configuration" );
 792  0
                 throw new MojoExecutionException( "The generated DOAP doesn't respect ASF rules, see above." );
 793  
             }
 794  
         }
 795  
 
 796  0
         if ( validate )
 797  
         {
 798  0
             List<String> errors = DoapUtil.validate( outputFile );
 799  0
             if ( !errors.isEmpty() )
 800  
             {
 801  0
                 getLog().error( "" );
 802  0
                 for ( String error : errors )
 803  
                 {
 804  0
                     getLog().error( error );
 805  
                 }
 806  0
                 getLog().error( "" );
 807  
 
 808  0
                 throw new MojoExecutionException( "Error parsing the generated DOAP file, see above." );
 809  
             }
 810  
         }
 811  0
     }
 812  
 
 813  
     /**
 814  
      * Write DOAP name.
 815  
      *
 816  
      * @param writer not null
 817  
      * @param project the Maven project, not null
 818  
      * @see <a href="http://usefulinc.com/ns/doap#name">http://usefulinc.com/ns/doap#name</a>
 819  
      */
 820  
     private void writeName( XMLWriter writer, MavenProject project )
 821  
     {
 822  0
         String name = DoapUtil.interpolate( doapOptions.getName(), project, settings );
 823  0
         if ( StringUtils.isEmpty( name ) )
 824  
         {
 825  0
             messages.addMessage( new String[] { "doapOptions", "name" }, null,
 826  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 827  0
             return;
 828  
         }
 829  
 
 830  0
         DoapUtil.writeComment( writer, "A name of something." );
 831  0
         if ( ASFExtOptionsUtil.isASFProject( project ) && !name.toLowerCase( Locale.ENGLISH ).startsWith( "apache" ) )
 832  
         {
 833  0
             name = "Apache " + name;
 834  
         }
 835  0
         DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "name", name );
 836  0
     }
 837  
 
 838  
     /**
 839  
      * Write DOAP description.
 840  
      *
 841  
      * @param writer not null
 842  
      * @param project the Maven project, not null
 843  
      * @see <a href="http://usefulinc.com/ns/doap#description">http://usefulinc.com/ns/doap#description</a>
 844  
      * @see <a href="http://usefulinc.com/ns/doap#shortdesc">http://usefulinc.com/ns/doap#shortdesc</a>
 845  
      */
 846  
     private void writeDescription( XMLWriter writer, MavenProject project )
 847  
     {
 848  0
         boolean addComment = false;
 849  0
         String description = DoapUtil.interpolate( doapOptions.getDescription(), project, settings );
 850  0
         if ( StringUtils.isEmpty( description ) )
 851  
         {
 852  0
             messages.addMessage( new String[] { "doapOptions", "description" }, null,
 853  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 854  
         }
 855  
         else
 856  
         {
 857  0
             DoapUtil.writeComment( writer, "Plain text description of a project, of 2-4 sentences in length." );
 858  0
             addComment = true;
 859  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "description", description, lang );
 860  
         }
 861  
 
 862  0
         String comment = "Short plain text description of a project.";
 863  0
         String shortdesc = DoapUtil.interpolate( doapOptions.getShortdesc(), project, settings );
 864  0
         if ( StringUtils.isEmpty( shortdesc ) )
 865  
         {
 866  0
             messages.addMessage( new String[] { "doapOptions", "shortdesc" }, null,
 867  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 868  0
             return;
 869  
         }
 870  0
         if ( description.equals( shortdesc ) )
 871  
         {
 872  
             // try to get the first 10 words of the description
 873  0
             String sentence = StringUtils.split( shortdesc, "." )[0];
 874  0
             if ( StringUtils.split( sentence, " " ).length > 10 )
 875  
             {
 876  0
                 messages.addMessage( new String[] { "doapOptions", "shortdesc" }, null,
 877  
                                      UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 878  0
                 return;
 879  
             }
 880  0
             if ( !addComment )
 881  
             {
 882  0
                 DoapUtil.writeComment( writer, comment );
 883  
             }
 884  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "shortdesc", sentence, lang );
 885  0
             return;
 886  
         }
 887  0
         if ( !addComment )
 888  
         {
 889  0
             DoapUtil.writeComment( writer, comment );
 890  
         }
 891  0
         DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "shortdesc", shortdesc, lang );
 892  0
     }
 893  
 
 894  
     /**
 895  
      * Write DOAP created.
 896  
      *
 897  
      * @param writer not null
 898  
      * @param project the Maven project, not null
 899  
      * @see <a href="http://usefulinc.com/ns/doap#created">http://usefulinc.com/ns/doap#created</a>
 900  
      */
 901  
     private void writeCreated( XMLWriter writer, MavenProject project )
 902  
     {
 903  0
         String created = DoapUtil.interpolate( doapOptions.getCreated(), project, settings );
 904  0
         if ( StringUtils.isEmpty( created ) )
 905  
         {
 906  0
             messages.addMessage( new String[] { "doapOptions", "created" }, null,
 907  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 908  0
             return;
 909  
         }
 910  
 
 911  
         try
 912  
         {
 913  0
             DOAP_DATE_FORMAT.parse( created );
 914  
         }
 915  0
         catch ( ParseException e )
 916  
         {
 917  0
             messages.addMessage( new String[] { "doapOptions", "created" }, null, UserMessages.INVALID_DATE );
 918  0
             return;
 919  0
         }
 920  
 
 921  0
         DoapUtil.writeComment( writer, "Date when something was created, in YYYY-MM-DD form. e.g. 2004-04-05" );
 922  0
         DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "created", created );
 923  0
     }
 924  
 
 925  
     /**
 926  
      * Write DOAP homepage and old-homepage.
 927  
      *
 928  
      * @param writer not null
 929  
      * @param project the Maven project, not null
 930  
      * @see <a href="http://usefulinc.com/ns/doap#homepage">http://usefulinc.com/ns/doap#homepage</a>
 931  
      * @see <a href="http://usefulinc.com/ns/doap#old-homepage">http://usefulinc.com/ns/doap#old-homepage</a>
 932  
      */
 933  
     private void writeHomepage( XMLWriter writer, MavenProject project )
 934  
     {
 935  0
         String homepage = DoapUtil.interpolate( doapOptions.getHomepage(), project, settings );
 936  0
         if ( StringUtils.isEmpty( homepage ) )
 937  
         {
 938  0
             messages.addMessage( new String[] { "doapOptions", "homepage" }, null,
 939  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 940  
         }
 941  
         else
 942  
         {
 943  
             try
 944  
             {
 945  0
                 new URL( homepage );
 946  
 
 947  0
                 DoapUtil.writeComment( writer, "URL of a project's homepage, associated with exactly one project." );
 948  0
                 DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "homepage", homepage );
 949  
             }
 950  0
             catch ( MalformedURLException e )
 951  
             {
 952  0
                 messages.addMessage( new String[] { "doapOptions", "homepage" }, homepage, UserMessages.INVALID_URL );
 953  0
             }
 954  
         }
 955  
 
 956  0
         if ( StringUtils.isNotEmpty( doapOptions.getOldHomepage() ) )
 957  
         {
 958  0
             String oldHomepage = DoapUtil.interpolate( doapOptions.getOldHomepage(), project, settings );
 959  0
             if ( StringUtils.isEmpty( oldHomepage ) )
 960  
             {
 961  0
                 return;
 962  
             }
 963  
 
 964  
             try
 965  
             {
 966  0
                 new URL( oldHomepage );
 967  
 
 968  0
                 DoapUtil.writeComment( writer, "URL of a project's past homepage, associated with exactly one project." );
 969  0
                 DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "old-homepage", oldHomepage );
 970  
             }
 971  0
             catch ( MalformedURLException e )
 972  
             {
 973  0
                 messages.addMessage( new String[] { "doapOptions", "oldHomepage" }, oldHomepage,
 974  
                                      UserMessages.INVALID_URL );
 975  0
             }
 976  
         }
 977  0
     }
 978  
 
 979  
     /**
 980  
      * Write DOAP programming-language.
 981  
      *
 982  
      * @param writer not null
 983  
      * @param project the Maven project, not null
 984  
      * @see <a href="http://usefulinc.com/ns/doap#programming-language">
 985  
      *      http://usefulinc.com/ns/doap#programming-language</a>
 986  
      */
 987  
     private void writeProgrammingLanguage( XMLWriter writer, MavenProject project )
 988  
     {
 989  0
         if ( StringUtils.isEmpty( doapOptions.getProgrammingLanguage() ) && StringUtils.isEmpty( language ) )
 990  
         {
 991  0
             messages.addMessage( new String[] { "doapOptions", "programmingLanguage" }, null,
 992  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 993  0
             return;
 994  
         }
 995  
 
 996  0
         boolean addComment = false;
 997  0
         String comment = "Programming language.";
 998  0
         if ( StringUtils.isNotEmpty( language ) ) // backward compatible
 999  
         {
 1000  0
             getLog().warn( "The <language/> parameter is deprecated, please use "
 1001  
                                + messages.toConfiguration( new String[] { "doapOptions", "programmingLanguage" }, null )
 1002  
                                + " parameter instead of." );
 1003  
 
 1004  0
             language = language.trim();
 1005  
 
 1006  0
             if ( asfExtOptions.isIncluded() )
 1007  
             {
 1008  0
                 String asfLanguage = ASFExtOptionsUtil.getProgrammingLanguageSupportedByASF( language );
 1009  0
                 if ( asfLanguage == null )
 1010  
                 {
 1011  0
                     messages.getErrorMessages().add( "The deprecated "
 1012  
                                                          + messages.toConfiguration( new String[] { "language" },
 1013  
                                                                                      language )
 1014  
                                                          + " parameter is not supported by ASF. Should be one of "
 1015  
                                                          + Arrays.toString( ASFExtOptionsUtil.PROGRAMMING_LANGUAGES ) );
 1016  
                 }
 1017  
                 else
 1018  
                 {
 1019  0
                     DoapUtil.writeComment( writer, comment );
 1020  0
                     addComment = true;
 1021  0
                     DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "programming-language",
 1022  
                                            asfLanguage.trim() );
 1023  
                 }
 1024  0
             }
 1025  
             else
 1026  
             {
 1027  0
                 DoapUtil.writeComment( writer, comment );
 1028  0
                 addComment = true;
 1029  0
                 DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "programming-language", language.trim() );
 1030  
             }
 1031  
         }
 1032  
 
 1033  0
         if ( StringUtils.isNotEmpty( doapOptions.getProgrammingLanguage() ) )
 1034  
         {
 1035  0
             String[] languages = StringUtils.split( doapOptions.getProgrammingLanguage(), "," );
 1036  0
             for ( String language : languages )
 1037  
             {
 1038  0
                 language = language.trim();
 1039  
 
 1040  0
                 if ( asfExtOptions.isIncluded() )
 1041  
                 {
 1042  0
                     String asfLanguage = ASFExtOptionsUtil.getProgrammingLanguageSupportedByASF( language );
 1043  0
                     if ( asfLanguage == null )
 1044  
                     {
 1045  0
                         messages.getErrorMessages().add( "The "
 1046  
                                                              + messages.toConfiguration( new String[] { "doapOptions",
 1047  
                                                                  "programmingLanguage" }, language )
 1048  
                                                              + " parameter is not supported by ASF. "
 1049  
                                                              + "Should be one of "
 1050  
                                                              + Arrays.toString( ASFExtOptionsUtil.PROGRAMMING_LANGUAGES ) );
 1051  
                     }
 1052  
                     else
 1053  
                     {
 1054  0
                         if ( !addComment )
 1055  
                         {
 1056  0
                             DoapUtil.writeComment( writer, comment );
 1057  0
                             addComment = true;
 1058  
                         }
 1059  0
                         DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "programming-language",
 1060  
                                                asfLanguage );
 1061  
                     }
 1062  0
                 }
 1063  
                 else
 1064  
                 {
 1065  0
                     if ( !addComment )
 1066  
                     {
 1067  0
                         DoapUtil.writeComment( writer, comment );
 1068  0
                         addComment = true;
 1069  
                     }
 1070  0
                     DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "programming-language", language );
 1071  
                 }
 1072  
             }
 1073  
         }
 1074  0
     }
 1075  
 
 1076  
     /**
 1077  
      * Write DOAP category.
 1078  
      *
 1079  
      * @param writer not null
 1080  
      * @param project the Maven project, not null
 1081  
      * @see <a href="http://usefulinc.com/ns/doap#category">http://usefulinc.com/ns/doap#category</a>
 1082  
      */
 1083  
     private void writeCategory( XMLWriter writer, MavenProject project )
 1084  
     {
 1085  0
         if ( StringUtils.isEmpty( doapOptions.getCategory() ) && StringUtils.isEmpty( category ) )
 1086  
         {
 1087  0
             messages.addMessage( new String[] { "doapOptions", "category" }, null,
 1088  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 1089  0
             return;
 1090  
         }
 1091  
 
 1092  
         // TODO: how to lookup category, map it, or just declare it.
 1093  0
         boolean addComment = false;
 1094  0
         String comment = "A category of project.";
 1095  0
         if ( StringUtils.isNotEmpty( category ) ) // backward compatible
 1096  
         {
 1097  0
             getLog().warn( "The <category/> parameter is deprecated, please use "
 1098  
                                + messages.toConfiguration( new String[] { "doapOptions", "category" }, null )
 1099  
                                + " parameter instead of." );
 1100  
 
 1101  0
             category = category.trim();
 1102  
 
 1103  0
             if ( asfExtOptions.isIncluded() )
 1104  
             {
 1105  0
                 String asfCategory = ASFExtOptionsUtil.getCategorySupportedByASF( category );
 1106  0
                 if ( asfCategory == null )
 1107  
                 {
 1108  0
                     messages.getErrorMessages().add( "The deprecated "
 1109  
                                                          + messages.toConfiguration( new String[] { "category" },
 1110  
                                                                                      category )
 1111  
                                                          + " parameter is not supported by ASF. Should be one of "
 1112  
                                                          + Arrays.toString( ASFExtOptionsUtil.CATEGORIES ) );
 1113  
                 }
 1114  
                 else
 1115  
                 {
 1116  0
                     DoapUtil.writeComment( writer, comment );
 1117  0
                     addComment = true;
 1118  0
                     DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "category",
 1119  
                                                       ASFExtOptionsUtil.CATEGORY_RESOURCE + asfCategory );
 1120  
                 }
 1121  0
             }
 1122  
             else
 1123  
             {
 1124  0
                 DoapUtil.writeComment( writer, comment );
 1125  0
                 addComment = true;
 1126  0
                 DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "category", category );
 1127  
             }
 1128  
         }
 1129  
 
 1130  0
         if ( StringUtils.isNotEmpty( doapOptions.getCategory() ) )
 1131  
         {
 1132  0
             String[] categories = StringUtils.split( doapOptions.getCategory(), "," );
 1133  0
             for ( String category : categories )
 1134  
             {
 1135  0
                 category = category.trim();
 1136  
 
 1137  0
                 if ( asfExtOptions.isIncluded() )
 1138  
                 {
 1139  0
                     String asfCategory = ASFExtOptionsUtil.getCategorySupportedByASF( category );
 1140  0
                     if ( asfCategory == null )
 1141  
                     {
 1142  0
                         messages.getErrorMessages().add( "The "
 1143  
                                                              + messages.toConfiguration( new String[] { "doapOptions",
 1144  
                                                                  "category" }, category )
 1145  
                                                              + " parameter is not supported by ASF. Should be one of "
 1146  
                                                              + Arrays.toString( ASFExtOptionsUtil.CATEGORIES ) );
 1147  
                     }
 1148  
                     else
 1149  
                     {
 1150  0
                         if ( !addComment )
 1151  
                         {
 1152  0
                             DoapUtil.writeComment( writer, comment );
 1153  0
                             addComment = true;
 1154  
                         }
 1155  0
                         DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "category",
 1156  
                                                           ASFExtOptionsUtil.CATEGORY_RESOURCE + asfCategory );
 1157  
                     }
 1158  0
                 }
 1159  
                 else
 1160  
                 {
 1161  0
                     if ( !addComment )
 1162  
                     {
 1163  0
                         DoapUtil.writeComment( writer, comment );
 1164  0
                         addComment = true;
 1165  
                     }
 1166  0
                     DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "category", category );
 1167  
                 }
 1168  
             }
 1169  
         }
 1170  0
     }
 1171  
 
 1172  
     /**
 1173  
      * Write DOAP download-page and download-mirror.
 1174  
      *
 1175  
      * @param writer not null
 1176  
      * @param project the Maven project, not null
 1177  
      * @see <a href="http://usefulinc.com/ns/doap#download-page">http://usefulinc.com/ns/doap#download-page</a>
 1178  
      * @see <a href="http://usefulinc.com/ns/doap#download-mirror">http://usefulinc.com/ns/doap#download-mirror</a>
 1179  
      */
 1180  
     private void writeDownloadPage( XMLWriter writer, MavenProject project )
 1181  
     {
 1182  0
         String downloadPage = DoapUtil.interpolate( doapOptions.getDownloadPage(), project, settings );
 1183  0
         if ( StringUtils.isEmpty( downloadPage ) )
 1184  
         {
 1185  0
             messages.addMessage( new String[] { "doapOptions", "downloadPage" }, null,
 1186  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 1187  0
             return;
 1188  
         }
 1189  
 
 1190  
         try
 1191  
         {
 1192  0
             new URL( downloadPage );
 1193  
 
 1194  0
             DoapUtil.writeComment( writer, "Download page." );
 1195  0
             DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "download-page", downloadPage );
 1196  
         }
 1197  0
         catch ( MalformedURLException e )
 1198  
         {
 1199  0
             messages.addMessage( new String[] { "doapOptions", "downloadPage" }, downloadPage, UserMessages.INVALID_URL );
 1200  0
         }
 1201  
 
 1202  0
         if ( StringUtils.isNotEmpty( doapOptions.getDownloadMirror() ) )
 1203  
         {
 1204  0
             boolean addComment = false;
 1205  0
             String[] downloadMirrors = StringUtils.split( doapOptions.getDownloadMirror(), "," );
 1206  0
             for ( String downloadMirror : downloadMirrors )
 1207  
             {
 1208  0
                 downloadMirror = downloadMirror.trim();
 1209  
 
 1210  
                 try
 1211  
                 {
 1212  0
                     new URL( downloadMirror );
 1213  
 
 1214  0
                     if ( !addComment )
 1215  
                     {
 1216  0
                         DoapUtil.writeComment( writer, "Mirror of software download web page." );
 1217  0
                         addComment = true;
 1218  
                     }
 1219  0
                     DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "download-mirror",
 1220  
                                                       downloadMirror );
 1221  
                 }
 1222  0
                 catch ( MalformedURLException e )
 1223  
                 {
 1224  0
                     messages.addMessage( new String[] { "doapOptions", "downloadMirror" }, downloadMirror,
 1225  
                                          UserMessages.INVALID_URL );
 1226  0
                 }
 1227  
             }
 1228  
         }
 1229  0
     }
 1230  
 
 1231  
     /**
 1232  
      * Write DOAP OS.
 1233  
      *
 1234  
      * @param writer not null
 1235  
      * @param project the Maven project, not null
 1236  
      * @see <a href="http://usefulinc.com/ns/doap#os">http://usefulinc.com/ns/doap#os</a>
 1237  
      */
 1238  
     private void writeOS( XMLWriter writer, MavenProject project )
 1239  
     {
 1240  0
         String os = DoapUtil.interpolate( doapOptions.getOs(), project, settings );
 1241  0
         if ( StringUtils.isEmpty( os ) )
 1242  
         {
 1243  0
             return;
 1244  
         }
 1245  
 
 1246  0
         DoapUtil.writeComment( writer, "Operating system that a project is limited to." );
 1247  0
         String[] oses = StringUtils.split( os, "," );
 1248  0
         for ( String os_ : oses )
 1249  
         {
 1250  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "os", os_.trim() );
 1251  
         }
 1252  0
     }
 1253  
 
 1254  
     /**
 1255  
      * Write DOAP screenshots.
 1256  
      *
 1257  
      * @param writer not null
 1258  
      * @param project the Maven project, not null
 1259  
      * @see <a href="http://usefulinc.com/ns/doap#screenshots">http://usefulinc.com/ns/doap#screenshots</a>
 1260  
      */
 1261  
     private void writeScreenshots( XMLWriter writer, MavenProject project )
 1262  
     {
 1263  0
         String screenshots = DoapUtil.interpolate( doapOptions.getScreenshots(), project, settings );
 1264  0
         if ( StringUtils.isEmpty( screenshots ) )
 1265  
         {
 1266  0
             return;
 1267  
         }
 1268  
 
 1269  0
         screenshots = screenshots.trim();
 1270  
         try
 1271  
         {
 1272  0
             new URL( screenshots );
 1273  
         }
 1274  0
         catch ( MalformedURLException e )
 1275  
         {
 1276  0
             messages.addMessage( new String[] { "doapOptions", "screenshots" }, screenshots, UserMessages.INVALID_URL );
 1277  0
             return;
 1278  0
         }
 1279  
 
 1280  0
         DoapUtil.writeComment( writer, "Web page with screenshots of project." );
 1281  0
         DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "screenshots", screenshots );
 1282  0
     }
 1283  
 
 1284  
     /**
 1285  
      * Write DOAP wiki.
 1286  
      *
 1287  
      * @param writer not null
 1288  
      * @param project the Maven project, not null
 1289  
      * @see <a href="http://usefulinc.com/ns/doap#wiki">http://usefulinc.com/ns/doap#wiki</a>
 1290  
      */
 1291  
     private void writeWiki( XMLWriter writer, MavenProject project )
 1292  
     {
 1293  0
         String wiki = DoapUtil.interpolate( doapOptions.getWiki(), project, settings );
 1294  0
         if ( StringUtils.isEmpty( wiki ) )
 1295  
         {
 1296  0
             return;
 1297  
         }
 1298  
 
 1299  0
         wiki = wiki.trim();
 1300  
         try
 1301  
         {
 1302  0
             new URL( wiki );
 1303  
         }
 1304  0
         catch ( MalformedURLException e )
 1305  
         {
 1306  0
             messages.addMessage( new String[] { "doapOptions", "wiki" }, wiki, UserMessages.INVALID_URL );
 1307  0
             return;
 1308  0
         }
 1309  
 
 1310  0
         DoapUtil.writeComment( writer, "URL of Wiki for collaborative discussion of project." );
 1311  0
         DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "wiki", wiki );
 1312  0
     }
 1313  
 
 1314  
     /**
 1315  
      * Write DOAP licenses.
 1316  
      *
 1317  
      * @param writer not null
 1318  
      * @param project the Maven project, not null
 1319  
      * @see <a href="http://usefulinc.com/ns/doap#license">http://usefulinc.com/ns/doap#license</a>
 1320  
      */
 1321  
     private void writeLicenses( XMLWriter writer, MavenProject project )
 1322  
     {
 1323  0
         String license = DoapUtil.interpolate( doapOptions.getLicense(), project, settings );
 1324  0
         if ( StringUtils.isEmpty( license ) )
 1325  
         {
 1326  0
             boolean added = false;
 1327  
             @SuppressWarnings( "unchecked" )
 1328  0
             List<License> licenses = project.getLicenses();
 1329  0
             if ( licenses.size() > 1 )
 1330  
             {
 1331  0
                 for ( int i = 1; i < licenses.size(); i++ )
 1332  
                 {
 1333  0
                     if ( StringUtils.isEmpty( licenses.get( i ).getUrl() ) )
 1334  
                     {
 1335  0
                         continue;
 1336  
                     }
 1337  
 
 1338  0
                     String licenseUrl = licenses.get( i ).getUrl().trim();
 1339  
                     try
 1340  
                     {
 1341  0
                         new URL( licenseUrl );
 1342  
 
 1343  0
                         DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "license", licenseUrl );
 1344  0
                         added = true;
 1345  
                     }
 1346  0
                     catch ( MalformedURLException e )
 1347  
                     {
 1348  0
                         messages.addMessage( new String[] { "project", "licenses", "license", "url" }, licenseUrl,
 1349  
                                              UserMessages.INVALID_URL );
 1350  0
                     }
 1351  
                 }
 1352  
             }
 1353  
 
 1354  0
             if ( !added )
 1355  
             {
 1356  0
                 messages.addMessage( new String[] { "doapOptions", "license" }, null,
 1357  
                                      UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 1358  
             }
 1359  0
             return;
 1360  
         }
 1361  
 
 1362  
         try
 1363  
         {
 1364  0
             new URL( license );
 1365  
 
 1366  0
             DoapUtil.writeComment( writer, "The URI of the license the software is distributed under." );
 1367  0
             DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "license", license );
 1368  
         }
 1369  0
         catch ( MalformedURLException e )
 1370  
         {
 1371  0
             messages.addMessage( new String[] { "doapOptions", "license" }, license, UserMessages.INVALID_URL );
 1372  0
         }
 1373  0
     }
 1374  
 
 1375  
     /**
 1376  
      * Write DOAP bug-database.
 1377  
      *
 1378  
      * @param writer not null
 1379  
      * @param project the Maven project, not null
 1380  
      * @see <a href="http://usefulinc.com/ns/doap#bug-database">http://usefulinc.com/ns/doap#bug-database</a>
 1381  
      */
 1382  
     private void writeBugDatabase( XMLWriter writer, MavenProject project )
 1383  
     {
 1384  0
         String bugDatabase = DoapUtil.interpolate( doapOptions.getBugDatabase(), project, settings );
 1385  0
         if ( StringUtils.isEmpty( bugDatabase ) )
 1386  
         {
 1387  0
             messages.addMessage( new String[] { "doapOptions", "bugDatabase" }, null,
 1388  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 1389  0
             return;
 1390  
         }
 1391  
 
 1392  
         try
 1393  
         {
 1394  0
             new URL( bugDatabase );
 1395  
 
 1396  0
             DoapUtil.writeComment( writer, "Bug database." );
 1397  0
             DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "bug-database", bugDatabase );
 1398  
         }
 1399  0
         catch ( MalformedURLException e )
 1400  
         {
 1401  0
             messages.addMessage( new String[] { "doapOptions", "bugDatabase" }, bugDatabase, UserMessages.INVALID_URL );
 1402  0
         }
 1403  0
     }
 1404  
 
 1405  
     /**
 1406  
      * Write DOAP mailing-list.
 1407  
      *
 1408  
      * @param writer not null
 1409  
      * @param project the Maven project, not null
 1410  
      * @see <a href="http://usefulinc.com/ns/doap#mailing-list">http://usefulinc.com/ns/doap#mailing-list</a>
 1411  
      * @see DoapOptions#getMailingList()
 1412  
      */
 1413  
     private void writeMailingList( XMLWriter writer, MavenProject project )
 1414  
     {
 1415  0
         String ml = DoapUtil.interpolate( doapOptions.getMailingList(), project, settings );
 1416  0
         if ( StringUtils.isEmpty( ml ) )
 1417  
         {
 1418  0
             messages.addMessage( new String[] { "doapOptions", "mailingList" }, null,
 1419  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 1420  0
             return;
 1421  
         }
 1422  
 
 1423  
         try
 1424  
         {
 1425  0
             new URL( ml );
 1426  
 
 1427  0
             DoapUtil.writeComment( writer, "Mailing lists." );
 1428  0
             DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "mailing-list", ml );
 1429  
         }
 1430  0
         catch ( MalformedURLException e )
 1431  
         {
 1432  0
             messages.addMessage( new String[] { "doapOptions", "mailingList" }, ml, UserMessages.INVALID_URL );
 1433  0
         }
 1434  0
     }
 1435  
 
 1436  
     /**
 1437  
      * Write all DOAP releases.
 1438  
      *
 1439  
      * @param writer not null
 1440  
      * @param project the Maven project, not null
 1441  
      * @throws MojoExecutionException if any
 1442  
      * @see <a href="http://usefulinc.com/ns/doap#release">http://usefulinc.com/ns/doap#release</a>
 1443  
      * @see <a href="http://usefulinc.com/ns/doap#Version">http://usefulinc.com/ns/doap#Version</a>
 1444  
      */
 1445  
     private void writeReleases( XMLWriter writer, MavenProject project )
 1446  
         throws MojoExecutionException
 1447  
     {
 1448  0
         Artifact artifact =
 1449  
             artifactFactory.createArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(), null,
 1450  
                                             project.getPackaging() );
 1451  0
         RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact );
 1452  
 
 1453  0
         for ( ArtifactRepository repo : remoteRepositories )
 1454  
         {
 1455  0
             if ( repo.isBlacklisted() )
 1456  
             {
 1457  0
                 continue;
 1458  
             }
 1459  0
             if ( repo.getSnapshots().isEnabled() )
 1460  
             {
 1461  0
                 continue;
 1462  
             }
 1463  0
             if ( repo.getReleases().isEnabled() )
 1464  
             {
 1465  
                 try
 1466  
                 {
 1467  0
                     repositoryMetadataManager.resolveAlways( metadata, localRepository, repo );
 1468  0
                     break;
 1469  
                 }
 1470  0
                 catch ( RepositoryMetadataResolutionException e )
 1471  
                 {
 1472  0
                     throw new MojoExecutionException( metadata.extendedToString()
 1473  
                         + " could not be retrieved from repositories due to an error: " + e.getMessage(), e );
 1474  
                 }
 1475  
             }
 1476  
         }
 1477  
 
 1478  0
         if ( metadata.getMetadata().getVersioning() == null )
 1479  
         {
 1480  0
             messages.getWarnMessages().add( "No versioning was found for " + artifact.getGroupId() + ":"
 1481  
                                                 + artifact.getArtifactId() + ". Ignored DOAP <release/> tag." );
 1482  0
             return;
 1483  
         }
 1484  
 
 1485  0
         List<String> versions = metadata.getMetadata().getVersioning().getVersions();
 1486  
 
 1487  
         // Recent releases in first
 1488  0
         Collections.reverse( versions );
 1489  0
         boolean addComment = false;
 1490  0
         int i = 0;
 1491  0
         for ( String version : versions )
 1492  
         {
 1493  0
             if ( !addComment )
 1494  
             {
 1495  0
                 DoapUtil.writeComment( writer, "Project releases." );
 1496  0
                 addComment = true;
 1497  
             }
 1498  
 
 1499  0
             DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "release" );
 1500  0
             DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "Version" );
 1501  
 
 1502  0
             DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "name" );
 1503  0
             if ( version.equals( metadata.getMetadata().getVersioning().getRelease() ) )
 1504  
             {
 1505  0
                 writer.writeText( "Latest stable release" );
 1506  
             }
 1507  
             else
 1508  
             {
 1509  0
                 writer.writeText( project.getName() + " - " + version );
 1510  
             }
 1511  0
             writer.endElement(); // name
 1512  
 
 1513  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "revision", version );
 1514  
 
 1515  
             // list all file release from all remote repos
 1516  0
             for ( ArtifactRepository repo : remoteRepositories )
 1517  
             {
 1518  0
                 Artifact artifactRelease =
 1519  
                     artifactFactory.createArtifact( project.getGroupId(), project.getArtifactId(), version, null,
 1520  
                                                     project.getPackaging() );
 1521  
 
 1522  0
                 if ( artifactRelease == null )
 1523  
                 {
 1524  0
                     continue;
 1525  
                 }
 1526  
 
 1527  0
                 String fileRelease = repo.getUrl() + "/" + repo.pathOf( artifactRelease );
 1528  
                 try
 1529  
                 {
 1530  0
                     DoapUtil.fetchURL( settings, new URL( fileRelease ) );
 1531  
                 }
 1532  0
                 catch ( IOException e )
 1533  
                 {
 1534  0
                     getLog().debug( "IOException :" + e.getMessage() );
 1535  0
                     continue;
 1536  0
                 }
 1537  0
                 DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "file-release", fileRelease );
 1538  
 
 1539  0
                 Date releaseDate = null;
 1540  
                 try
 1541  
                 {
 1542  0
                     releaseDate =
 1543  
                         REPOSITORY_DATE_FORMAT.parse( metadata.getMetadata().getVersioning().getLastUpdated() );
 1544  
                 }
 1545  0
                 catch ( ParseException e )
 1546  
                 {
 1547  0
                     getLog().error( "Unable to parse date '" + metadata.getMetadata().getVersioning().getLastUpdated()
 1548  
                                         + "'" );
 1549  0
                     continue;
 1550  0
                 }
 1551  
 
 1552  
                 // See MDOAP-11
 1553  0
                 if ( i == 0 )
 1554  
                 {
 1555  0
                     DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "created",
 1556  
                                            DOAP_DATE_FORMAT.format( releaseDate ) );
 1557  
                 }
 1558  0
             }
 1559  
 
 1560  0
             writer.endElement(); // Version
 1561  0
             writer.endElement(); // release
 1562  
 
 1563  0
             i++;
 1564  
         }
 1565  0
     }
 1566  
 
 1567  
     /**
 1568  
      * Write all DOAP repositories.
 1569  
      *
 1570  
      * @param writer not null
 1571  
      * @param project the Maven project, not null
 1572  
      * @see <a href="http://usefulinc.com/ns/doap#Repository">http://usefulinc.com/ns/doap#Repository</a>
 1573  
      * @see <a href="http://usefulinc.com/ns/doap#CVSRepository">http://usefulinc.com/ns/doap#CVSRepository</a>
 1574  
      * @see <a href="http://usefulinc.com/ns/doap#SVNRepository">http://usefulinc.com/ns/doap#SVNRepository</a>
 1575  
      */
 1576  
     private void writeSourceRepositories( XMLWriter writer, MavenProject project )
 1577  
     {
 1578  0
         String anonymousConnection = DoapUtil.interpolate( doapOptions.getScmAnonymous(), project, settings );
 1579  0
         if ( StringUtils.isEmpty( anonymousConnection ) )
 1580  
         {
 1581  0
             messages.addMessage( new String[] { "doapOptions", "scmAnonymousConnection" }, null,
 1582  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 1583  
         }
 1584  
         else
 1585  
         {
 1586  0
             DoapUtil.writeComment( writer, "Anonymous Source Repository." );
 1587  
 
 1588  
             try
 1589  
             {
 1590  0
                 new URL( anonymousConnection );
 1591  
 
 1592  0
                 DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "repository" );
 1593  0
                 DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "Repository" );
 1594  0
                 DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "location", anonymousConnection );
 1595  0
                 writer.endElement(); // Repository
 1596  0
                 writer.endElement(); // repository
 1597  
             }
 1598  0
             catch ( MalformedURLException e )
 1599  
             {
 1600  0
                 writeSourceRepository( writer, project, anonymousConnection );
 1601  0
             }
 1602  
         }
 1603  
 
 1604  0
         String devConnection = DoapUtil.interpolate( doapOptions.getScmDeveloper(), project, settings );
 1605  0
         if ( StringUtils.isEmpty( devConnection ) )
 1606  
         {
 1607  0
             messages.addMessage( new String[] { "doapOptions", "scmDeveloperConnection" }, null,
 1608  
                                  UserMessages.REQUIRED_BY_ASF_OR_RECOMMENDED );
 1609  
         }
 1610  
         else
 1611  
         {
 1612  0
             DoapUtil.writeComment( writer, "Developer Source Repository." );
 1613  
 
 1614  
             try
 1615  
             {
 1616  0
                 new URL( devConnection );
 1617  
 
 1618  0
                 DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "repository" );
 1619  0
                 DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "Repository" );
 1620  0
                 DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "location", devConnection );
 1621  0
                 writer.endElement(); // Repository
 1622  0
                 writer.endElement(); // repository
 1623  
             }
 1624  0
             catch ( MalformedURLException e )
 1625  
             {
 1626  0
                 writeSourceRepository( writer, project, devConnection );
 1627  0
             }
 1628  
         }
 1629  0
     }
 1630  
 
 1631  
     /**
 1632  
      * Write a DOAP repository, for instance:
 1633  
      *
 1634  
      * <pre>
 1635  
      *   &lt;repository&gt;
 1636  
      *     &lt;SVNRepository&gt;
 1637  
      *       &lt;location rdf:resource="http://svn.apache.org/repos/asf/maven/components/trunk/"/&gt;
 1638  
      *       &lt;browse rdf:resource="http://svn.apache.org/viewcvs.cgi/maven/components/trunk/"/&gt;
 1639  
      *     &lt;/SVNRepository&gt;
 1640  
      *   &lt;/repository&gt;
 1641  
      * </pre>
 1642  
      *
 1643  
      * @param writer not null
 1644  
      * @param project the Maven project, not null
 1645  
      * @param connection not null
 1646  
      * @see <a href="http://usefulinc.com/ns/doap#Repository">http://usefulinc.com/ns/doap#Repository</a>
 1647  
      * @see <a href="http://usefulinc.com/ns/doap#CVSRepository">http://usefulinc.com/ns/doap#CVSRepository</a>
 1648  
      * @see <a href="http://usefulinc.com/ns/doap#SVNRepository">http://usefulinc.com/ns/doap#SVNRepository</a>
 1649  
      */
 1650  
     private void writeSourceRepository( XMLWriter writer, MavenProject project, String connection )
 1651  
     {
 1652  0
         ScmRepository repository = getScmRepository( connection );
 1653  
 
 1654  0
         DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "repository" );
 1655  
 
 1656  0
         if ( isScmSystem( repository, "cvs" ) )
 1657  
         {
 1658  0
             DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "CVSRepository" );
 1659  
 
 1660  0
             CvsScmProviderRepository cvsRepo = (CvsScmProviderRepository) repository.getProviderRepository();
 1661  
 
 1662  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "anon-root", cvsRepo.getCvsRoot() );
 1663  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "module", cvsRepo.getModule() );
 1664  0
         }
 1665  0
         else if ( isScmSystem( repository, "svn" ) )
 1666  
         {
 1667  0
             DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "SVNRepository" );
 1668  
 
 1669  0
             SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) repository.getProviderRepository();
 1670  
 
 1671  0
             DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "location", svnRepo.getUrl() );
 1672  0
         }
 1673  
         else
 1674  
         {
 1675  
             /*
 1676  
              * Supported DOAP repositories actually unsupported by SCM: BitKeeper
 1677  
              * (http://usefulinc.com/ns/doap#BKRepository) Arch (http://usefulinc.com/ns/doap#ArchRepository) Other SCM
 1678  
              * repos are unsupported by DOAP.
 1679  
              */
 1680  0
             DoapUtil.writeStartElement( writer, doapOptions.getXmlnsPrefix(), "Repository" );
 1681  
 
 1682  0
             if ( connection.length() < 4 )
 1683  
             {
 1684  0
                 throw new IllegalArgumentException( "The source repository connection is too short." );
 1685  
             }
 1686  
 
 1687  0
             DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "location",
 1688  
                                               connection.substring( 4 ) );
 1689  
         }
 1690  
 
 1691  0
         DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "browse", project.getScm().getUrl() );
 1692  
 
 1693  0
         writer.endElement(); // CVSRepository || SVNRepository || Repository
 1694  0
         writer.endElement(); // repository
 1695  0
     }
 1696  
 
 1697  
     /**
 1698  
      * Write all DOAP persons.
 1699  
      *
 1700  
      * @param writer not null
 1701  
      * @param contributors list of developers or contributors
 1702  
      */
 1703  
     private void writeContributors( XMLWriter writer, List<Contributor> contributors )
 1704  
     {
 1705  0
         if ( contributors == null || contributors.isEmpty() )
 1706  
         {
 1707  0
             return;
 1708  
         }
 1709  
 
 1710  0
         boolean isDeveloper = Developer.class.isAssignableFrom( contributors.get( 0 ).getClass() );
 1711  0
         if ( isDeveloper )
 1712  
         {
 1713  0
             DoapUtil.writeComment( writer, "Main committers." );
 1714  
         }
 1715  
         else
 1716  
         {
 1717  0
             DoapUtil.writeComment( writer, "Contributed persons." );
 1718  
         }
 1719  
 
 1720  0
         List<Contributor> maintainers = DoapUtil.getContributorsWithMaintainerRole( i18n, contributors );
 1721  0
         List<Contributor> developers = DoapUtil.getContributorsWithDeveloperRole( i18n, contributors );
 1722  0
         List<Contributor> documenters = DoapUtil.getContributorsWithDocumenterRole( i18n, contributors );
 1723  0
         List<Contributor> translators = DoapUtil.getContributorsWithTranslatorRole( i18n, contributors );
 1724  0
         List<Contributor> testers = DoapUtil.getContributorsWithTesterRole( i18n, contributors );
 1725  0
         List<Contributor> helpers = DoapUtil.getContributorsWithHelperRole( i18n, contributors );
 1726  0
         List<Contributor> unknowns = DoapUtil.getContributorsWithUnknownRole( i18n, contributors );
 1727  
 
 1728  
         // By default, all developers are maintainers and contributors are helpers
 1729  0
         if ( isDeveloper )
 1730  
         {
 1731  0
             maintainers.addAll( unknowns );
 1732  
         }
 1733  
         else
 1734  
         {
 1735  0
             helpers.addAll( unknowns );
 1736  
         }
 1737  
 
 1738  
         // all alphabetical
 1739  0
         if ( developers.size() != 0 )
 1740  
         {
 1741  0
             writeContributor( writer, developers, "developer" );
 1742  
         }
 1743  0
         if ( documenters.size() != 0 )
 1744  
         {
 1745  0
             writeContributor( writer, documenters, "documenter" );
 1746  
         }
 1747  0
         if ( helpers.size() != 0 )
 1748  
         {
 1749  0
             writeContributor( writer, helpers, "helper" );
 1750  
         }
 1751  0
         if ( maintainers.size() != 0 )
 1752  
         {
 1753  0
             writeContributor( writer, maintainers, "maintainer" );
 1754  
         }
 1755  0
         if ( testers.size() != 0 )
 1756  
         {
 1757  0
             writeContributor( writer, testers, "tester" );
 1758  
         }
 1759  0
         if ( translators.size() != 0 )
 1760  
         {
 1761  0
             writeContributor( writer, translators, "translator" );
 1762  
         }
 1763  0
     }
 1764  
 
 1765  
     /**
 1766  
      * Write a DOAP maintainer or developer or documenter or translator or tester or helper, for instance:
 1767  
      *
 1768  
      * <pre>
 1769  
      *   &lt;maintainer&gt;
 1770  
      *     &lt;foaf:Person&gt;
 1771  
      *       &lt;foaf:name&gt;Emmanuel Venisse&lt;/foaf:name&gt;
 1772  
      *       &lt;foaf:mbox rdf:resource="mailto:evenisse@apache.org"/&gt;
 1773  
      *     &lt;/foaf:Person&gt;
 1774  
      *   &lt;/maintainer&gt;
 1775  
      * </pre>
 1776  
      *
 1777  
      * @param writer not null
 1778  
      * @param developersOrContributors list of <code>{@link Developer}/{@link Contributor}</code>
 1779  
      * @param doapType not null
 1780  
      * @see #writeContributor(XMLWriter, Object, String)
 1781  
      */
 1782  
     private void writeContributor( XMLWriter writer, List<Contributor> developersOrContributors, String doapType )
 1783  
     {
 1784  0
         if ( developersOrContributors == null || developersOrContributors.isEmpty() )
 1785  
         {
 1786  0
             return;
 1787  
         }
 1788  
 
 1789  0
         sortContributors( developersOrContributors );
 1790  
 
 1791  0
         for ( Contributor developersOrContributor : developersOrContributors )
 1792  
         {
 1793  0
             writeContributor( writer, developersOrContributor, doapOptions.getXmlnsPrefix(), doapType );
 1794  
         }
 1795  0
     }
 1796  
 
 1797  
     /**
 1798  
      * Writer a single developer or contributor
 1799  
      *
 1800  
      * @param writer not null
 1801  
      * @param xmlsPrefix could be null
 1802  
      * @param developerOrContributor not null, instance of <code>{@link Developer}/{@link Contributor}</code>
 1803  
      * @param doapType not null
 1804  
      * @see <a href="http://usefulinc.com/ns/doap#maintainer">http://usefulinc.com/ns/doap#maintainer</a>
 1805  
      * @see <a href="http://usefulinc.com/ns/doap#developer">http://usefulinc.com/ns/doap#developer</a>
 1806  
      * @see <a href="http://usefulinc.com/ns/doap#documenter">http://usefulinc.com/ns/doap#documenter</a>
 1807  
      * @see <a href="http://usefulinc.com/ns/doap#translator">http://usefulinc.com/ns/doap#translator</a>
 1808  
      * @see <a href="http://usefulinc.com/ns/doap#tester">http://usefulinc.com/ns/doap#tester</a>
 1809  
      * @see <a href="http://usefulinc.com/ns/doap#helper">http://usefulinc.com/ns/doap#helper</a>
 1810  
      * @see <a href="http://xmlns.com/foaf/0.1/Person">http://xmlns.com/foaf/0.1/Person</a>
 1811  
      * @see <a href="http://xmlns.com/foaf/0.1/name">http://xmlns.com/foaf/0.1/name</a>
 1812  
      * @see <a href="http://xmlns.com/foaf/0.1/mbox">http://xmlns.com/foaf/0.1/mbox</a>
 1813  
      * @see <a href="http://xmlns.com/foaf/0.1/Organization">http://xmlns.com/foaf/0.1/Organization</a>
 1814  
      * @see <a href="http://xmlns.com/foaf/0.1/homepage">http://xmlns.com/foaf/0.1/homepage</a>
 1815  
      */
 1816  
     private void writeContributor( XMLWriter writer, Contributor developerOrContributor, String xmlsPrefix,
 1817  
                                    String doapType )
 1818  
     {
 1819  0
         if ( developerOrContributor == null )
 1820  
         {
 1821  0
             return;
 1822  
         }
 1823  
 
 1824  0
         if ( StringUtils.isEmpty( doapType ) )
 1825  
         {
 1826  0
             throw new IllegalArgumentException( "doapType is required." );
 1827  
         }
 1828  
 
 1829  0
         String name = developerOrContributor.getName();
 1830  0
         String email = developerOrContributor.getEmail();
 1831  0
         String organization = developerOrContributor.getOrganization();
 1832  0
         String organizationUrl = developerOrContributor.getOrganizationUrl();
 1833  0
         String homepage = developerOrContributor.getUrl();
 1834  0
         String nodeId = null;
 1835  
 
 1836  
         // Name is required to write doap
 1837  0
         if ( StringUtils.isEmpty( name ) )
 1838  
         {
 1839  0
             messages.addMessage( new String[] { "project", "developers|contributors", "developer|contributor", "name" },
 1840  
                                  null, UserMessages.REQUIRED );
 1841  0
             return;
 1842  
         }
 1843  
 
 1844  0
         if ( !StringUtils.isEmpty( organization ) || !StringUtils.isEmpty( organizationUrl ) )
 1845  
         {
 1846  0
             DoapUtil.Organization doapOrganization = DoapUtil.addOrganization( organization, organizationUrl );
 1847  0
             nodeId = DoapUtil.getNodeId();
 1848  0
             doapOrganization.addMember( nodeId );
 1849  
         }
 1850  
 
 1851  0
         DoapUtil.writeStartElement( writer, xmlsPrefix, doapType );
 1852  0
         DoapUtil.writeStartElement( writer, "foaf", "Person" );
 1853  0
         if ( StringUtils.isNotEmpty( nodeId ) )
 1854  
         {
 1855  0
             writer.addAttribute( "rdf:nodeID", nodeId );
 1856  
         }
 1857  0
         DoapUtil.writeStartElement( writer, "foaf", "name" );
 1858  0
         writer.writeText( name );
 1859  0
         writer.endElement(); // foaf:name
 1860  0
         if ( StringUtils.isNotEmpty( email ) )
 1861  
         {
 1862  0
             if ( DoapUtil.isValidEmail( email ) )
 1863  
             {
 1864  0
                 DoapUtil.writeRdfResourceElement( writer, "foaf", "mbox", "mailto:" + email );
 1865  
             }
 1866  
             else
 1867  
             {
 1868  0
                 messages.addMessage( new String[] { "project", "developers|contributors", "developer|contributor",
 1869  
                     "email" }, null, UserMessages.INVALID_EMAIL );
 1870  
             }
 1871  
         }
 1872  0
         if ( StringUtils.isNotEmpty( organization ) && StringUtils.isNotEmpty( organizationUrl ) )
 1873  
         {
 1874  
             try
 1875  
             {
 1876  0
                 new URL( organizationUrl );
 1877  
 
 1878  0
                 DoapUtil.addOrganization( organization, organizationUrl );
 1879  
             }
 1880  0
             catch ( MalformedURLException e )
 1881  
             {
 1882  0
                 messages.addMessage( new String[] { "project", "developers|contributors", "developer|contributor",
 1883  
                     "organizationUrl" }, organizationUrl, UserMessages.INVALID_URL );
 1884  0
             }
 1885  
         }
 1886  0
         if ( StringUtils.isNotEmpty( homepage ) )
 1887  
         {
 1888  
             try
 1889  
             {
 1890  0
                 new URL( homepage );
 1891  
 
 1892  0
                 DoapUtil.writeRdfResourceElement( writer, "foaf", "homepage", homepage );
 1893  
             }
 1894  0
             catch ( MalformedURLException e )
 1895  
             {
 1896  0
                 messages.addMessage( new String[] { "project", "developers|contributors", "developer|contributor",
 1897  
                     "homepage" }, homepage, UserMessages.INVALID_URL );
 1898  0
             }
 1899  
         }
 1900  0
         writer.endElement(); // foaf:Person
 1901  0
         writer.endElement(); // doapType
 1902  0
     }
 1903  
 
 1904  
     /**
 1905  
      * Return a <code>SCM repository</code> defined by a given url
 1906  
      *
 1907  
      * @param scmUrl an SCM URL
 1908  
      * @return a valid SCM repository or null
 1909  
      */
 1910  
     private ScmRepository getScmRepository( String scmUrl )
 1911  
     {
 1912  0
         ScmRepository repo = null;
 1913  0
         if ( !StringUtils.isEmpty( scmUrl ) )
 1914  
         {
 1915  
             try
 1916  
             {
 1917  0
                 repo = scmManager.makeScmRepository( scmUrl );
 1918  
             }
 1919  0
             catch ( NoSuchScmProviderException e )
 1920  
             {
 1921  0
                 if ( getLog().isDebugEnabled() )
 1922  
                 {
 1923  0
                     getLog().debug( e.getMessage(), e );
 1924  
                 }
 1925  
             }
 1926  0
             catch ( ScmRepositoryException e )
 1927  
             {
 1928  0
                 if ( getLog().isDebugEnabled() )
 1929  
                 {
 1930  0
                     getLog().debug( e.getMessage(), e );
 1931  
                 }
 1932  0
             }
 1933  
         }
 1934  
 
 1935  0
         return repo;
 1936  
     }
 1937  
 
 1938  
     /**
 1939  
      * Write the ASF extensions
 1940  
      *
 1941  
      * @param writer not null
 1942  
      * @param project the Maven project, not null
 1943  
      * @see <a href="http://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/asfext">
 1944  
      *      http://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/asfext</a>
 1945  
      * @see <a href="http://projects.apache.org/docs/pmc.html">http://projects.apache.org/docs/pmc.html</a>
 1946  
      */
 1947  
     private void writeASFext( XMLWriter writer, MavenProject project )
 1948  
     {
 1949  0
         if ( !asfExtOptions.isIncluded() )
 1950  
         {
 1951  0
             return;
 1952  
         }
 1953  
 
 1954  0
         DoapUtil.writeComment( writer, "ASF extension." );
 1955  
 
 1956  
         // asfext:pmc
 1957  0
         String pmc = DoapUtil.interpolate( asfExtOptions.getPmc(), project, settings );
 1958  0
         if ( StringUtils.isNotEmpty( pmc ) )
 1959  
         {
 1960  0
             DoapUtil.writeRdfResourceElement( writer, asfExtOptions.getXmlnsPrefix(), "pmc", pmc );
 1961  
         }
 1962  
         else
 1963  
         {
 1964  0
             messages.addMessage( new String[] { "asfExtOptions", "pmc" }, null, UserMessages.REQUIRED_BY_ASF );
 1965  
         }
 1966  
 
 1967  
         // asfext:name
 1968  0
         String name = DoapUtil.interpolate( asfExtOptions.getName(), project, settings );
 1969  0
         if ( StringUtils.isNotEmpty( name ) )
 1970  
         {
 1971  0
             if ( !name.toLowerCase( Locale.ENGLISH ).trim().startsWith( "apache" ) )
 1972  
             {
 1973  0
                 name = "Apache " + name;
 1974  
             }
 1975  0
             DoapUtil.writeElement( writer, asfExtOptions.getXmlnsPrefix(), "name", name );
 1976  
         }
 1977  
         else
 1978  
         {
 1979  0
             messages.addMessage( new String[] { "asfExtOptions", "name" }, null, UserMessages.REQUIRED_BY_ASF );
 1980  
         }
 1981  
 
 1982  0
         String homepage = DoapUtil.interpolate( doapOptions.getHomepage(), project, settings );
 1983  0
         if ( StringUtils.isNotEmpty( homepage ) )
 1984  
         {
 1985  
             try
 1986  
             {
 1987  0
                 new URL( homepage );
 1988  
 
 1989  0
                 DoapUtil.writeRdfResourceElement( writer, "foaf", "homepage", homepage );
 1990  
             }
 1991  0
             catch ( MalformedURLException e )
 1992  
             {
 1993  0
                 messages.addMessage( new String[] { "doapOptions", "homepage" }, homepage, UserMessages.INVALID_URL );
 1994  0
             }
 1995  
         }
 1996  
 
 1997  
         // asfext:charter
 1998  0
         if ( StringUtils.isEmpty( asfExtOptions.getCharter() ) )
 1999  
         {
 2000  0
             messages.addMessage( new String[] { "asfExtOptions", "charter" }, null, UserMessages.REQUIRED_BY_ASF );
 2001  
         }
 2002  
         else
 2003  
         {
 2004  0
             DoapUtil.writeElement( writer, asfExtOptions.getXmlnsPrefix(), "charter", asfExtOptions.getCharter() );
 2005  
         }
 2006  
 
 2007  
         // asfext:chair
 2008  
         @SuppressWarnings( "unchecked" )
 2009  0
         List<Developer> developers = new ArrayList<Developer>( project.getDevelopers() );
 2010  0
         sortContributors( developers );
 2011  
 
 2012  0
         if ( StringUtils.isNotEmpty( asfExtOptions.getChair() ) )
 2013  
         {
 2014  0
             DoapUtil.writeStartElement( writer, asfExtOptions.getXmlnsPrefix(), "chair" );
 2015  0
             DoapUtil.writeStartElement( writer, "foaf", "Person" );
 2016  0
             DoapUtil.writeStartElement( writer, "foaf", "name" );
 2017  0
             writer.writeText( asfExtOptions.getChair() );
 2018  0
             writer.endElement(); // foaf:name
 2019  0
             writer.endElement(); // foaf:Person
 2020  0
             writer.endElement(); // asfext:chair
 2021  
         }
 2022  
         else
 2023  
         {
 2024  0
             Developer chair = ASFExtOptionsUtil.findChair( developers );
 2025  0
             if ( chair != null )
 2026  
             {
 2027  0
                 writeContributor( writer, chair, asfExtOptions.getXmlnsPrefix(), "chair" );
 2028  0
                 developers.remove( chair );
 2029  
             }
 2030  
             else
 2031  
             {
 2032  0
                 messages.addMessage( new String[] { "asfExtOptions", "chair" }, null, UserMessages.REQUIRED_BY_ASF );
 2033  
             }
 2034  
         }
 2035  
 
 2036  
         // asfext:member
 2037  0
         if ( developers != null && developers.size() > 0 )
 2038  
         {
 2039  0
             List<Developer> pmcMembers = ASFExtOptionsUtil.findPMCMembers( developers );
 2040  0
             for ( Developer pmcMember : pmcMembers )
 2041  
             {
 2042  0
                 writeContributor( writer, pmcMember, asfExtOptions.getXmlnsPrefix(), "member" );
 2043  
             }
 2044  
         }
 2045  
 
 2046  0
         writeASFImplements( writer );
 2047  
 
 2048  
         @SuppressWarnings( "unchecked" )
 2049  0
         Map<String, String> map = asfExtOptions.getExtra();
 2050  0
         writeExtra( writer, project, "Extra ASFExt vocabulary.", map, asfExtOptions.getXmlnsPrefix() );
 2051  0
     }
 2052  
 
 2053  
     /**
 2054  
      * Write the ASF implements.
 2055  
      *
 2056  
      * @param writer not null
 2057  
      * @see <a href="http://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/asfext">
 2058  
      *      http://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/asfext</a>
 2059  
      * @see <a href="http://projects.apache.org/docs/standards.html">http://projects.apache.org/docs/standards.html</a>
 2060  
      */
 2061  
     private void writeASFImplements( XMLWriter writer )
 2062  
     {
 2063  0
         if ( asfExtOptions.getStandards() == null || asfExtOptions.getStandards().isEmpty() )
 2064  
         {
 2065  0
             return;
 2066  
         }
 2067  
 
 2068  0
         for ( Standard standard : asfExtOptions.getStandards() )
 2069  
         {
 2070  0
             DoapUtil.writeStartElement( writer, asfExtOptions.getXmlnsPrefix(), "implements" );
 2071  0
             DoapUtil.writeStartElement( writer, asfExtOptions.getXmlnsPrefix(), "Standard" );
 2072  
 
 2073  0
             if ( StringUtils.isEmpty( standard.getTitle() ) )
 2074  
             {
 2075  0
                 messages.addMessage( new String[] { "asfExtOptions", "standards", "title" }, null,
 2076  
                                      UserMessages.REQUIRED_BY_ASF );
 2077  
             }
 2078  
             else
 2079  
             {
 2080  0
                 DoapUtil.writeElement( writer, asfExtOptions.getXmlnsPrefix(), "title", standard.getTitle().trim() );
 2081  
             }
 2082  
 
 2083  0
             if ( StringUtils.isEmpty( standard.getBody() ) )
 2084  
             {
 2085  0
                 messages.addMessage( new String[] { "asfExtOptions", "standards", "body" }, null,
 2086  
                                      UserMessages.REQUIRED_BY_ASF );
 2087  
             }
 2088  
             else
 2089  
             {
 2090  0
                 DoapUtil.writeElement( writer, asfExtOptions.getXmlnsPrefix(), "body", standard.getBody().trim() );
 2091  
             }
 2092  
 
 2093  0
             if ( StringUtils.isEmpty( standard.getId() ) )
 2094  
             {
 2095  0
                 messages.addMessage( new String[] { "asfExtOptions", "standards", "id" }, null,
 2096  
                                      UserMessages.REQUIRED_BY_ASF );
 2097  
             }
 2098  
             else
 2099  
             {
 2100  0
                 DoapUtil.writeElement( writer, asfExtOptions.getXmlnsPrefix(), "id", standard.getId().trim() );
 2101  
             }
 2102  
 
 2103  0
             if ( StringUtils.isNotEmpty( standard.getUrl() ) )
 2104  
             {
 2105  0
                 String standardUrl = standard.getUrl().trim();
 2106  
                 try
 2107  
                 {
 2108  0
                     new URL( standardUrl );
 2109  
 
 2110  0
                     DoapUtil.writeElement( writer, asfExtOptions.getXmlnsPrefix(), "url", standardUrl );
 2111  
                 }
 2112  0
                 catch ( MalformedURLException e )
 2113  
                 {
 2114  0
                     messages.addMessage( new String[] { "asfExtOptions", "standards", "url" }, standardUrl,
 2115  
                                          UserMessages.INVALID_URL );
 2116  0
                 }
 2117  
             }
 2118  
 
 2119  0
             writer.endElement(); // asfext:Standard
 2120  0
             writer.endElement(); // asfext:implements
 2121  
         }
 2122  0
     }
 2123  
 
 2124  
     /**
 2125  
      * Write a Foaf Organization, for instance:
 2126  
      *
 2127  
      * <pre>
 2128  
      *   &lt;<foaf:Organization&gt;
 2129  
      *     &lt;foaf:name&gt;YoyoDyne&lt;/foaf:name&gt;
 2130  
      *     &lt;foaf:homepage rdf:resource="http://yoyodyne.example.org"/&gt;
 2131  
      *     &lt;foaf:member rdf:nodeID="benny_profane"&gt;
 2132  
      *   &lt;/foaf:Organization&gt;
 2133  
      * </pre>
 2134  
      *
 2135  
      * @param writer not null
 2136  
      * @param developersOrContributors list of <code>{@link Developer}/{@link Contributor}</code>
 2137  
      * @param doapType not null
 2138  
      * @see #writeContributor(XMLWriter, Object, String)
 2139  
      */
 2140  
     private void writeOrganizations( XMLWriter writer )
 2141  
     {
 2142  0
         Set<Entry<String, DoapUtil.Organization>> organizations = DoapUtil.getOrganizations();
 2143  
 
 2144  0
         for ( Entry<String, DoapUtil.Organization> organizationEntry : organizations )
 2145  
         {
 2146  0
             DoapUtil.Organization organization = organizationEntry.getValue();
 2147  
 
 2148  0
             DoapUtil.writeStartElement( writer, "foaf", "Organization" );
 2149  0
             if ( !StringUtils.isEmpty( organization.getName() ) )
 2150  
             {
 2151  0
                 DoapUtil.writeElement( writer, "foaf", "name", organization.getName() );
 2152  
             }
 2153  0
             if ( !StringUtils.isEmpty( organization.getUrl() ) )
 2154  
             {
 2155  
                 try
 2156  
                 {
 2157  0
                     new URL( organization.getUrl() );
 2158  
 
 2159  0
                     DoapUtil.writeRdfResourceElement( writer, "foaf", "homepage", organization.getUrl() );
 2160  
                 }
 2161  0
                 catch ( MalformedURLException e )
 2162  
                 {
 2163  0
                     messages.errorMessages.add( "The organization URL " + organization.getUrl()
 2164  
                         + " is not a valid URL." );
 2165  0
                 }
 2166  
             }
 2167  0
             List<String> members = organization.getMembers();
 2168  0
             for ( String member : members )
 2169  
             {
 2170  0
                 DoapUtil.writeRdfNodeIdElement( writer, "foaf", "member", member );
 2171  
             }
 2172  0
             writer.endElement(); // foaf:Organization
 2173  0
         }
 2174  0
     }
 2175  
 
 2176  
     /**
 2177  
      * Write DOAP audience.
 2178  
      *
 2179  
      * @param writer not null
 2180  
      * @see <a href="http://usefulinc.com/ns/doap#audience">http://usefulinc.com/ns/doap#audience</a>
 2181  
      * @since 1.1
 2182  
      */
 2183  
     private void writeAudience( XMLWriter writer )
 2184  
     {
 2185  0
         String audience = DoapUtil.interpolate( doapOptions.getAudience(), project, settings );
 2186  0
         if ( StringUtils.isEmpty( audience ) )
 2187  
         {
 2188  0
             return;
 2189  
         }
 2190  
 
 2191  0
         DoapUtil.writeComment( writer, "Audience." );
 2192  0
         DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "audience", audience );
 2193  0
     }
 2194  
 
 2195  
     /**
 2196  
      * Write DOAP blog.
 2197  
      *
 2198  
      * @param writer not null
 2199  
      * @see <a href="http://usefulinc.com/ns/doap#blog">http://usefulinc.com/ns/doap#blog</a>
 2200  
      * @since 1.1
 2201  
      */
 2202  
     private void writeBlog( XMLWriter writer )
 2203  
     {
 2204  0
         String blog = DoapUtil.interpolate( doapOptions.getBlog(), project, settings );
 2205  0
         if ( StringUtils.isEmpty( doapOptions.getBlog() ) )
 2206  
         {
 2207  0
             return;
 2208  
         }
 2209  
 
 2210  0
         blog = blog.trim();
 2211  
         try
 2212  
         {
 2213  0
             new URL( blog );
 2214  
         }
 2215  0
         catch ( MalformedURLException e )
 2216  
         {
 2217  0
             messages.addMessage( new String[] { "doapOptions", "blog" }, blog, UserMessages.INVALID_URL );
 2218  0
             return;
 2219  0
         }
 2220  
 
 2221  0
         DoapUtil.writeComment( writer, "Blog page." );
 2222  0
         DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "blog", blog );
 2223  0
     }
 2224  
 
 2225  
     /**
 2226  
      * Write DOAP plateform.
 2227  
      *
 2228  
      * @param writer not null
 2229  
      * @see <a href="http://usefulinc.com/ns/doap#plateform">http://usefulinc.com/ns/doap#plateform</a>
 2230  
      * @since 1.1
 2231  
      */
 2232  
     private void writePlateform( XMLWriter writer )
 2233  
     {
 2234  0
         if ( StringUtils.isEmpty( doapOptions.getPlatform() ) )
 2235  
         {
 2236  0
             return;
 2237  
         }
 2238  
 
 2239  0
         DoapUtil.writeComment( writer, "Platform." );
 2240  0
         String[] platforms = StringUtils.split( doapOptions.getPlatform(), "," );
 2241  0
         for ( String platform : platforms )
 2242  
         {
 2243  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "platform", platform.trim() );
 2244  
         }
 2245  0
     }
 2246  
 
 2247  
     /**
 2248  
      * Write DOAP vendor.
 2249  
      *
 2250  
      * @param writer not null
 2251  
      * @param project the Maven project, not null
 2252  
      * @see <a href="http://usefulinc.com/ns/doap#vendor">http://usefulinc.com/ns/doap#vendor</a>
 2253  
      * @since 1.1
 2254  
      */
 2255  
     private void writeVendor( XMLWriter writer, MavenProject project )
 2256  
     {
 2257  0
         String vendor = DoapUtil.interpolate( doapOptions.getVendor(), project, settings );
 2258  0
         if ( StringUtils.isEmpty( vendor ) )
 2259  
         {
 2260  0
             return;
 2261  
         }
 2262  
 
 2263  0
         DoapUtil.writeComment( writer, "Vendor." );
 2264  0
         DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "vendor", vendor );
 2265  0
     }
 2266  
 
 2267  
     /**
 2268  
      * Write DOAP language.
 2269  
      *
 2270  
      * @param writer not null
 2271  
      * @see <a href="http://usefulinc.com/ns/doap#language">http://usefulinc.com/ns/doap#language</a>
 2272  
      * @since 1.1
 2273  
      */
 2274  
     private void writeLanguage( XMLWriter writer )
 2275  
     {
 2276  0
         if ( StringUtils.isEmpty( doapOptions.getLanguage() ) )
 2277  
         {
 2278  0
             return;
 2279  
         }
 2280  
 
 2281  0
         boolean addComment = false;
 2282  0
         String[] languages = StringUtils.split( doapOptions.getLanguage(), "," );
 2283  0
         for ( String language : languages )
 2284  
         {
 2285  0
             language = language.trim();
 2286  
 
 2287  0
             if ( Arrays.binarySearch( Locale.getISOLanguages(), language ) < 0 )
 2288  
             {
 2289  0
                 messages.addMessage( new String[] { "doapOptions", "languages" }, language,
 2290  
                                      UserMessages.INVALID_ISO_DATE );
 2291  0
                 continue;
 2292  
             }
 2293  
 
 2294  0
             if ( !addComment )
 2295  
             {
 2296  0
                 DoapUtil.writeComment( writer, "Language." );
 2297  0
                 addComment = true;
 2298  
             }
 2299  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "language", language );
 2300  
         }
 2301  0
     }
 2302  
 
 2303  
     /**
 2304  
      * Write DOAP service-endpoint.
 2305  
      *
 2306  
      * @param writer not null
 2307  
      * @see <a href="http://usefulinc.com/ns/doap#service-endpoint">http://usefulinc.com/ns/doap#service-endpoint</a>
 2308  
      * @since 1.1
 2309  
      */
 2310  
     private void writeServiceEndpoint( XMLWriter writer )
 2311  
     {
 2312  0
         String serviceEndpoint = DoapUtil.interpolate( doapOptions.getServiceEndpoint(), project, settings );
 2313  0
         if ( StringUtils.isEmpty( serviceEndpoint ) )
 2314  
         {
 2315  0
             return;
 2316  
         }
 2317  
 
 2318  0
         serviceEndpoint = serviceEndpoint.trim();
 2319  
         try
 2320  
         {
 2321  0
             new URL( serviceEndpoint );
 2322  
         }
 2323  0
         catch ( MalformedURLException e )
 2324  
         {
 2325  0
             messages.addMessage( new String[] { "doapOptions", "serviceEndpoint" }, serviceEndpoint,
 2326  
                                  UserMessages.INVALID_URL );
 2327  0
             return;
 2328  0
         }
 2329  
 
 2330  0
         DoapUtil.writeComment( writer, "Service endpoint." );
 2331  0
         DoapUtil.writeRdfResourceElement( writer, doapOptions.getXmlnsPrefix(), "service-endpoint", serviceEndpoint );
 2332  0
     }
 2333  
 
 2334  
     /**
 2335  
      * Write DOAP implements.
 2336  
      *
 2337  
      * @param writer not null
 2338  
      * @see <a href="http://usefulinc.com/ns/doap#implements">http://usefulinc.com/ns/doap#implements</a>
 2339  
      * @since 1.1
 2340  
      */
 2341  
     private void writeImplements( XMLWriter writer )
 2342  
     {
 2343  0
         if ( StringUtils.isEmpty( doapOptions.getImplementations() ) )
 2344  
         {
 2345  0
             return;
 2346  
         }
 2347  
 
 2348  0
         DoapUtil.writeComment( writer, "Implements." );
 2349  0
         String[] implementations = StringUtils.split( doapOptions.getImplementations(), "," );
 2350  0
         for ( String implementation : implementations )
 2351  
         {
 2352  0
             DoapUtil.writeElement( writer, doapOptions.getXmlnsPrefix(), "implements", implementation.trim() );
 2353  
         }
 2354  0
     }
 2355  
 
 2356  
     /**
 2357  
      * Write extra for DOAP or any extension.
 2358  
      *
 2359  
      * @param writer not null
 2360  
      * @param project not null
 2361  
      * @param comment not null
 2362  
      * @param map not null
 2363  
      * @param xmlnsPrefix not null
 2364  
      * @since 1.1
 2365  
      */
 2366  
     private void writeExtra( XMLWriter writer, MavenProject project, String comment, Map<String, String> map,
 2367  
                              String xmlnsPrefix )
 2368  
     {
 2369  0
         if ( map == null || map.isEmpty() )
 2370  
         {
 2371  0
             return;
 2372  
         }
 2373  
 
 2374  0
         boolean addComment = false;
 2375  0
         for ( Map.Entry<String, String> entry : map.entrySet() )
 2376  
         {
 2377  0
             String key = entry.getKey();
 2378  0
             String value = entry.getValue();
 2379  
 
 2380  0
             if ( value == null )
 2381  
             {
 2382  0
                 continue;
 2383  
             }
 2384  
 
 2385  0
             String interpolatedValue = DoapUtil.interpolate( value, project, settings );
 2386  0
             if ( interpolatedValue == null )
 2387  
             {
 2388  0
                 continue;
 2389  
             }
 2390  
 
 2391  0
             if ( !addComment )
 2392  
             {
 2393  0
                 DoapUtil.writeComment( writer, comment );
 2394  0
                 addComment = true;
 2395  
             }
 2396  
 
 2397  
             try
 2398  
             {
 2399  0
                 new URL( interpolatedValue );
 2400  
 
 2401  0
                 DoapUtil.writeRdfResourceElement( writer, xmlnsPrefix, key, interpolatedValue );
 2402  
             }
 2403  0
             catch ( MalformedURLException e )
 2404  
             {
 2405  0
                 DoapUtil.writeElement( writer, xmlnsPrefix, key, interpolatedValue );
 2406  0
             }
 2407  0
         }
 2408  0
     }
 2409  
 
 2410  
     /**
 2411  
      * Write the extra DOAP extensions.
 2412  
      *
 2413  
      * @param writer not null
 2414  
      * @since 1.1
 2415  
      */
 2416  
     private void writeExtensions( XMLWriter writer )
 2417  
     {
 2418  0
         if ( !( extOptions != null && extOptions.length > 0 && !extOptions[0].getExtensions().isEmpty() ) )
 2419  
         {
 2420  0
             return;
 2421  
         }
 2422  
 
 2423  0
         for ( ExtOptions extOption : extOptions )
 2424  
         {
 2425  
             @SuppressWarnings( "unchecked" )
 2426  0
             Map<String, String> map = extOption.getExtensions();
 2427  0
             writeExtra( writer, project, "Other extension vocabulary.", map, extOption.getXmlnsPrefix() );
 2428  
         }
 2429  0
     }
 2430  
 
 2431  
     // ----------------------------------------------------------------------
 2432  
     // Static methods
 2433  
     // ----------------------------------------------------------------------
 2434  
 
 2435  
     /**
 2436  
      * Convenience method that return true is the defined <code>SCM repository</code> is a known provider.
 2437  
      * <p>
 2438  
      * Actually, we fully support Clearcase, CVS, Perforce, Starteam, SVN by the maven-scm-providers component.
 2439  
      * </p>
 2440  
      *
 2441  
      * @param scmRepository a SCM repository
 2442  
      * @param scmProvider a SCM provider name
 2443  
      * @return true if the provider of the given SCM repository is equal to the given scm provider.
 2444  
      * @see <a href="http://svn.apache.org/repos/asf/maven/scm/trunk/maven-scm-providers/">maven-scm-providers</a>
 2445  
      */
 2446  
     private static boolean isScmSystem( ScmRepository scmRepository, String scmProvider )
 2447  
     {
 2448  0
         if ( StringUtils.isEmpty( scmProvider ) )
 2449  
         {
 2450  0
             return false;
 2451  
         }
 2452  
 
 2453  0
         if ( scmRepository != null && scmProvider.equalsIgnoreCase( scmRepository.getProvider() ) )
 2454  
         {
 2455  0
             return true;
 2456  
         }
 2457  
 
 2458  0
         return false;
 2459  
     }
 2460  
 
 2461  
     /**
 2462  
      * Sort Contributor by name or Developer by id.
 2463  
      *
 2464  
      * @param contributors not null
 2465  
      * @since 1.1
 2466  
      */
 2467  
     @SuppressWarnings( { "unchecked", "rawtypes" } )
 2468  
     private static void sortContributors( List contributors )
 2469  
     {
 2470  0
         Collections.sort( contributors, new Comparator<Contributor>()
 2471  0
         {
 2472  
             public int compare( Contributor contributor1, Contributor contributor2 )
 2473  
             {
 2474  0
                 if ( contributor1 == contributor2 )
 2475  
                 {
 2476  0
                     return 0;
 2477  
                 }
 2478  
 
 2479  0
                 if ( contributor1 == null && contributor2 != null )
 2480  
                 {
 2481  0
                     return -1;
 2482  
                 }
 2483  0
                 if ( contributor1 != null && contributor2 == null )
 2484  
                 {
 2485  0
                     return +1;
 2486  
                 }
 2487  
 
 2488  0
                 if ( Developer.class.isAssignableFrom( contributor1.getClass() )
 2489  
                     && Developer.class.isAssignableFrom( contributor2.getClass() ) )
 2490  
                 {
 2491  0
                     Developer developer1 = (Developer) contributor1;
 2492  0
                     Developer developer2 = (Developer) contributor2;
 2493  
 
 2494  0
                     if ( developer1.getId() == null && developer2.getId() != null )
 2495  
                     {
 2496  0
                         return -1;
 2497  
                     }
 2498  0
                     if ( developer1.getId() != null && developer2.getId() == null )
 2499  
                     {
 2500  0
                         return +1;
 2501  
                     }
 2502  
 
 2503  0
                     return developer1.getId().compareTo( developer2.getId() );
 2504  
                 }
 2505  
 
 2506  0
                 if ( contributor1.getName() == null && contributor2.getName() != null )
 2507  
                 {
 2508  0
                     return -1;
 2509  
                 }
 2510  0
                 if ( contributor1.getName() != null && contributor2.getName() == null )
 2511  
                 {
 2512  0
                     return +1;
 2513  
                 }
 2514  0
                 return contributor1.getName().compareTo( contributor2.getName() );
 2515  
             }
 2516  
         } );
 2517  0
     }
 2518  
 
 2519  
     /**
 2520  
      * Encapsulates all user messages.
 2521  
      *
 2522  
      * @since 1.1
 2523  
      */
 2524  0
     private class UserMessages
 2525  
     {
 2526  
         public static final int REQUIRED = 10;
 2527  
 
 2528  
         public static final int REQUIRED_BY_ASF_OR_RECOMMENDED = 11;
 2529  
 
 2530  
         public static final int REQUIRED_BY_ASF = 12;
 2531  
 
 2532  
         public static final int RECOMMENDED = 20;
 2533  
 
 2534  
         public static final int INVALID_URL = 30;
 2535  
 
 2536  
         public static final int INVALID_DATE = 31;
 2537  
 
 2538  
         public static final int INVALID_ISO_DATE = 32;
 2539  
 
 2540  
         public static final int INVALID_EMAIL = 33;
 2541  
 
 2542  0
         private List<String> errorMessages = new ArrayList<String>();
 2543  
 
 2544  0
         private List<String> warnMessages = new ArrayList<String>();
 2545  
 
 2546  
         /**
 2547  
          * @return the error messages
 2548  
          */
 2549  
         public List<String> getErrorMessages()
 2550  
         {
 2551  0
             return errorMessages;
 2552  
         }
 2553  
 
 2554  
         /**
 2555  
          * @return the warn messages
 2556  
          */
 2557  
         public List<String> getWarnMessages()
 2558  
         {
 2559  0
             return warnMessages;
 2560  
         }
 2561  
 
 2562  
         /**
 2563  
          * @param tags not null
 2564  
          * @param value could be null
 2565  
          * @param errorId positive id
 2566  
          */
 2567  
         protected void addMessage( String[] tags, String value, int errorId )
 2568  
         {
 2569  0
             if ( tags == null )
 2570  
             {
 2571  0
                 throw new IllegalArgumentException( "tags is required" );
 2572  
             }
 2573  
 
 2574  0
             boolean isPom = false;
 2575  0
             if ( tags[0].equalsIgnoreCase( "project" ) )
 2576  
             {
 2577  0
                 isPom = true;
 2578  
             }
 2579  0
             switch ( errorId )
 2580  
             {
 2581  
                 case REQUIRED:
 2582  0
                     errorMessages.add( "A " + toConfiguration( tags, null ) + "  parameter is required." );
 2583  0
                     break;
 2584  
                 case REQUIRED_BY_ASF_OR_RECOMMENDED:
 2585  0
                     if ( isPom )
 2586  
                     {
 2587  0
                         if ( asfExtOptions.isIncluded() )
 2588  
                         {
 2589  0
                             errorMessages.add( "A POM " + toConfiguration( tags, null ) + " value is required by ASF." );
 2590  
                         }
 2591  
                         else
 2592  
                         {
 2593  0
                             warnMessages.add( "No POM " + toConfiguration( tags, null )
 2594  
                                 + " value is defined, it is highly recommended to have one." );
 2595  
                         }
 2596  
                     }
 2597  
                     else
 2598  
                     {
 2599  0
                         if ( asfExtOptions.isIncluded() )
 2600  
                         {
 2601  0
                             errorMessages.add( "A " + toConfiguration( tags, null ) + " parameter is required by ASF." );
 2602  
                         }
 2603  
                         else
 2604  
                         {
 2605  0
                             warnMessages.add( "No " + toConfiguration( tags, null )
 2606  
                                 + " parameter defined, it is highly recommended to have one." );
 2607  
                         }
 2608  
                     }
 2609  0
                     break;
 2610  
                 case REQUIRED_BY_ASF:
 2611  0
                     if ( isPom )
 2612  
                     {
 2613  0
                         errorMessages.add( "A POM " + toConfiguration( tags, null ) + " value is required by ASF." );
 2614  
                     }
 2615  
                     else
 2616  
                     {
 2617  0
                         errorMessages.add( "A " + toConfiguration( tags, null ) + " parameter is required by ASF." );
 2618  
                     }
 2619  0
                     break;
 2620  
                 case RECOMMENDED:
 2621  0
                     warnMessages.add( "No " + toConfiguration( tags, null )
 2622  
                         + " parameter defined, it is highly recommended to have one." );
 2623  0
                     break;
 2624  
                 case INVALID_URL:
 2625  0
                     if ( isPom )
 2626  
                     {
 2627  0
                         errorMessages.add( "The POM " + toConfiguration( tags, value ) + " value is not a valid URL." );
 2628  
                     }
 2629  
                     else
 2630  
                     {
 2631  0
                         errorMessages.add( "The " + toConfiguration( tags, value ) + " parameter is not a valid URL." );
 2632  
                     }
 2633  0
                     break;
 2634  
                 case INVALID_DATE:
 2635  0
                     errorMessages.add( "The " + toConfiguration( tags, value ) + " parameter should be in YYYY-MM-DD." );
 2636  0
                     break;
 2637  
                 case INVALID_EMAIL:
 2638  0
                     errorMessages.add( "The POM " + toConfiguration( tags, value ) + " value is not a valid email." );
 2639  0
                     break;
 2640  
                 case INVALID_ISO_DATE:
 2641  0
                     errorMessages.add( "The " + toConfiguration( tags, value )
 2642  
                         + " parameter is not a valid ISO language." );
 2643  0
                     break;
 2644  
                 default:
 2645  0
                     throw new IllegalArgumentException( "Unknown errorId=" + errorId );
 2646  
             }
 2647  0
         }
 2648  
 
 2649  
         /**
 2650  
          * @param tags not null
 2651  
          * @param value of the last tag, could be null
 2652  
          * @return the XML configuration defined in tags.
 2653  
          */
 2654  
         protected String toConfiguration( String[] tags, String value )
 2655  
         {
 2656  0
             if ( tags == null )
 2657  
             {
 2658  0
                 throw new IllegalArgumentException( "tags is required" );
 2659  
             }
 2660  
 
 2661  0
             StringBuffer sb = new StringBuffer();
 2662  0
             for ( int i = 0; i < tags.length; i++ )
 2663  
             {
 2664  0
                 if ( i == tags.length - 1 && StringUtils.isEmpty( value ) )
 2665  
                 {
 2666  0
                     sb.append( "<" ).append( tags[i] ).append( "/>" );
 2667  
                 }
 2668  
                 else
 2669  
                 {
 2670  0
                     sb.append( "<" ).append( tags[i] ).append( ">" );
 2671  
                 }
 2672  
             }
 2673  0
             if ( StringUtils.isNotEmpty( value ) )
 2674  
             {
 2675  0
                 sb.append( value );
 2676  
             }
 2677  0
             for ( int i = tags.length - 1; i >= 0; i-- )
 2678  
             {
 2679  0
                 if ( !( i == tags.length - 1 && StringUtils.isEmpty( value ) ) )
 2680  
                 {
 2681  0
                     sb.append( "</" ).append( tags[i] ).append( ">" );
 2682  
                 }
 2683  
             }
 2684  
 
 2685  0
             return sb.toString();
 2686  
         }
 2687  
     }
 2688  
 }