You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by br...@apache.org on 2006/03/22 07:02:55 UTC

svn commit: r387745 [1/2] - in /maven/sandbox/plugins/changelog-maven-plugin: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/maven/ src/main/java/org/apache/maven/changelog/ src/main/resources/ sr...

Author: brett
Date: Tue Mar 21 22:02:52 2006
New Revision: 387745

URL: http://svn.apache.org/viewcvs?rev=387745&view=rev
Log:
Import of changelog-maven-plugin code from https://svn.codehaus.org/mojo/trunk/mojo/changelog-maven-plugin/, r1708

Code authored by people that have an Apache CLA on file: 
* Edwin Punzalan (Initial contribution derived from code under https://svn.apache.org/repos/asf/maven/maven-1/plugins/trunk/changelog)
* Trygve Laugstol
* Brett Porter
* Emmanuel Venisse
* Brian Fox

Contains code donated under the Apache License 2.0 by:
* Julian Wood <wo...@ucalgary.ca> - r973, handle date and time being non-sequentially parsed by the handler

All code is under the Apache License v2.0

Added:
    maven/sandbox/plugins/changelog-maven-plugin/
    maven/sandbox/plugins/changelog-maven-plugin/pom.xml   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLog.java   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogHandler.java   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogReport.java   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/DeveloperActivityReport.java   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityComparator.java   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityReport.java   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/
    maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/scm-activity.properties   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/site/
    maven/sandbox/plugins/changelog-maven-plugin/src/site/apt/
    maven/sandbox/plugins/changelog-maven-plugin/src/site/apt/howto.apt   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/site/resources/
    maven/sandbox/plugins/changelog-maven-plugin/src/site/resources/sample-changelog.html   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/site/resources/sample-dev-activity.html   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/site/resources/sample-file-activity.html   (with props)
    maven/sandbox/plugins/changelog-maven-plugin/src/site/site.xml   (with props)

Added: maven/sandbox/plugins/changelog-maven-plugin/pom.xml
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/pom.xml?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/pom.xml (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/pom.xml Tue Mar 21 22:02:52 2006
@@ -0,0 +1,176 @@
+<project>
+  <parent>
+    <artifactId>mojo</artifactId>
+    <groupId>org.codehaus.mojo</groupId>
+    <version>7</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>changelog-maven-plugin</artifactId>
+  <packaging>maven-plugin</packaging>
+  <name>Maven Changelog Plug-in</name>
+  <version>2.0-beta-2-SNAPSHOT</version>
+  <description>Produce SCM changelog reports.</description>
+  <developers>
+    <developer>
+      <id>kaz</id>
+      <name>Pete Kazmier</name>
+      <email>pete-apache-dev@kazmier.com</email>
+      <organization></organization>
+      <roles>
+        <role>Documentation</role>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>epugh</id>
+      <name>Eric Pugh</name>
+      <email>epugh@opensourceconnections.com</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>emmanuel@venisse.net</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@zenplex.com</email>
+      <organization>Zenplex</organization>
+      <roles>
+        <role>Architect</role>
+        <role>Release Manager</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dlr</id>
+      <name>Daniel Rall</name>
+      <email>dlr@finemaltcoding.com</email>
+      <organization>CollabNet, Inc.</organization>
+      <roles>
+        <role>Java Developer</role>
+        <role>Documentation</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>felipeal</id>
+      <name>Felipe Leme</name>
+      <email>maven@felipeal.net</email>
+      <organization>Falcon Informatica</organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+      <timezone>-3</timezone>
+    </developer>
+  </developers>
+  <contributors>
+    <contributor>
+      <name>David Jackman</name>
+    </contributor>
+  </contributors>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.reporting</groupId>
+      <artifactId>maven-reporting-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-model</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>regexp</groupId>
+      <artifactId>regexp</artifactId>
+      <version>1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant</artifactId>
+      <version>1.6.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.reporting</groupId>
+      <artifactId>maven-reporting-impl</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>netbeans</groupId>
+      <artifactId>cvslib</artifactId>
+      <version>3.6</version>
+    </dependency>
+    <dependency>
+      <groupId>doxia</groupId>
+      <artifactId>doxia-sink-api</artifactId>
+      <version>1.0-alpha-5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-settings</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-api</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-manager-plexus</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-bazaar</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-clearcase</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <!-- Replace this cvs provider by a pure java cvs provider when it will be available -->
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-cvsexe</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-local</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-perforce</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-starteam</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-svnexe</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-vss</artifactId>
+      <version>1.0-beta-3-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Propchange: maven/sandbox/plugins/changelog-maven-plugin/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/pom.xml
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLog.java
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLog.java?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLog.java (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLog.java Tue Mar 21 22:02:52 2006
@@ -0,0 +1,66 @@
+package org.apache.maven.changelog;
+
+/*
+ * Copyright 2001-2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// java imports
+
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Change log task. It uses a ChangeLogGenerator and ChangeLogParser to create
+ * a Collection of ChangeLogEntry objects, which are used to produce an XML
+ * output that represents the list of changes.
+ *
+ * @author <a href="mailto:glenn@somanetworks.com">Glenn McAllister</a>
+ * @author <a href="mailto:jeff.martin@synamic.co.uk">Jeff Martin</a>
+ * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
+ * @author <a href="mailto:dion@multitask.com.au">dIon Gillard</a>
+ * @author <a href="mailto:bodewig@apache.org">Stefan Bodewig</a>
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Id$
+ */
+public class ChangeLog
+{
+    /**
+     * parses a previously generated changelog xml document and return its changed sets
+     *
+     * @param stream the changelog xml document
+     * @return changelog sets parsed from the xml document
+     * @throws ParserConfigurationException when instantiation of the SAX parser failed
+     * @throws SAXException                 when an error occurred while parsing the xml document
+     * @throws IOException                  when an error occurred while accessing the xml document
+     */
+    public static List loadChangedSets( InputStream stream )
+        throws ParserConfigurationException, SAXException, IOException
+    {
+        SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+
+        List changeLogSets = new ArrayList();
+
+        parser.parse( stream, new ChangeLogHandler( changeLogSets ) );
+
+        return changeLogSets;
+    }
+} // end of ChangeLog

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLog.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLog.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogHandler.java
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogHandler.java?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogHandler.java (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogHandler.java Tue Mar 21 22:02:52 2006
@@ -0,0 +1,222 @@
+package org.apache.maven.changelog;
+
+/*
+ * Copyright 2001-2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.scm.ChangeFile;
+import org.apache.maven.scm.ChangeSet;
+import org.apache.maven.scm.command.changelog.ChangeLogSet;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedList;
+
+/**
+ * Change log generated xml parser.  SAXParser listener for processing a previously generated xml into several
+ * change log sets.
+ */
+public class ChangeLogHandler
+    extends DefaultHandler
+{
+    private Collection changeSets;
+
+    private String bufData = "";
+
+    private ChangeFile bufFile;
+
+    private ChangeSet bufEntry;
+
+    private LinkedList bufEntries;
+
+    private ChangeLogSet bufSet;
+
+    private String currentPattern;
+
+    /**
+     * contructor
+     *
+     * @param changeSets collection object to store all change sets found within the xml document
+     */
+    public ChangeLogHandler( Collection changeSets )
+    {
+        this.changeSets = changeSets;
+    }
+
+    /**
+     * @see org.xml.sax.helpers.DefaultHandler#characters(char[],int,int)
+     */
+    public void characters( char[] ch, int start, int length )
+        throws SAXException
+    {
+        bufData += new String( ch, start, length );
+    }
+
+    /**
+     * @see org.xml.sax.helpers.DefaultHandler#endElement(String,String,String)
+     */
+    public void endElement( String uri, String localName, String qName )
+        throws SAXException
+    {
+        if ( "changeset".equals( qName ) )
+        {
+            changeSets.add( bufSet );
+        }
+
+        if ( "changelog-entry".equals( qName ) )
+        {
+            bufEntries.add( bufEntry );
+        }
+
+        if ( "file".equals( qName ) )
+        {
+            bufEntry.addFile( bufFile );
+        }
+        else if ( "date".equals( qName ) )
+        {
+            try
+            {
+                long ms = 0;
+                if ( bufEntry.getDate() != null )
+                {
+                    ms = bufEntry.getDate().getTime();
+                }
+                bufEntry.setDate( new Date( ms + new SimpleDateFormat( currentPattern ).parse( bufData ).getTime() ) );
+            }
+            catch ( ParseException e )
+            {
+                throw new SAXException( e );
+            }
+        }
+        else if ( "time".equals( qName ) )
+        {
+            try
+            {
+                long ms = 0;
+                if ( bufEntry.getDate() != null )
+                {
+                    ms = bufEntry.getDate().getTime();
+                }
+                bufEntry.setDate( new Date( ms + new SimpleDateFormat( currentPattern ).parse( bufData ).getTime() ) );
+            }
+            catch ( ParseException e )
+            {
+                throw new SAXException( e );
+            }
+        }
+        else if ( "author".equals( qName ) )
+        {
+            bufEntry.setAuthor( bufData );
+        }
+        else if ( "msg".equals( qName ) )
+        {
+            bufEntry.setComment( bufData );
+        }
+
+        if ( "revision".equals( qName ) )
+        {
+            bufFile.setRevision( bufData );
+        }
+        else if ( "name".equals( qName ) )
+        {
+            bufFile.setName( bufData );
+        }
+    }
+
+    /**
+     * @see org.xml.sax.helpers.DefaultHandler#startElement(String,String,String,Attributes)
+     */
+    public void startElement( String uri, String localName, String qName, Attributes attributes )
+        throws SAXException
+    {
+        bufData = "";
+
+        if ( "file".equals( qName ) )
+        {
+            bufFile = new ChangeFile( "" );
+        }
+        else if ( "changelog-entry".equals( qName ) )
+        {
+            bufEntry = new ChangeSet();
+        }
+        else if ( "date".equals( qName ) )
+        {
+            currentPattern = attributes.getValue( "pattern" );
+            if ( currentPattern == null )
+            {
+                currentPattern = "yyyy-MM-dd";
+            }
+        }
+        else if ( "time".equals( qName ) )
+        {
+            currentPattern = attributes.getValue( "pattern" );
+            if ( currentPattern == null )
+            {
+                currentPattern = "HH:mm:ss";
+            }
+        }
+        else if ( "changeset".equals( qName ) )
+        {
+            bufEntries = new LinkedList();
+
+            currentPattern = attributes.getValue( "datePattern" );
+            if ( currentPattern == null )
+            {
+                currentPattern = "yyyy-MM-dd";
+            }
+
+            SimpleDateFormat formatter = new SimpleDateFormat( currentPattern );
+
+            String start = attributes.getValue( "start" );
+
+            String end = attributes.getValue( "end" );
+
+            Date startDate = null;
+
+            Date endDate = null;
+
+            if ( start != null )
+            {
+                try
+                {
+                    startDate = formatter.parse( start );
+                }
+                catch ( ParseException e )
+                {
+                    throw new SAXException( "Can't parse start date '" + start + "'.", e );
+                }
+            }
+
+            if ( end != null )
+            {
+                try
+                {
+                    endDate = formatter.parse( end );
+                }
+                catch ( ParseException e )
+                {
+                    throw new SAXException( "Can't parse end date '" + end + "'.", e );
+                }
+            }
+
+            bufSet = new ChangeLogSet( bufEntries, startDate, endDate );
+        }
+    }
+}

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogHandler.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogReport.java
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogReport.java?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogReport.java (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogReport.java Tue Mar 21 22:02:52 2006
@@ -0,0 +1,1224 @@
+package org.apache.maven.changelog;
+
+/*
+ * Copyright 2001-2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.AbstractMavenReport;
+import org.apache.maven.reporting.MavenReportException;
+import org.apache.maven.scm.ChangeFile;
+import org.apache.maven.scm.ChangeSet;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
+import org.apache.maven.scm.command.changelog.ChangeLogSet;
+import org.apache.maven.scm.manager.ScmManager;
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
+import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
+import org.apache.maven.scm.repository.ScmRepository;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.codehaus.doxia.sink.Sink;
+import org.codehaus.doxia.site.renderer.SiteRenderer;
+import org.codehaus.plexus.util.StringUtils;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+
+
+/**
+ * @goal changelog
+ * @description A Maven 2.0 Changelog report plugin
+ */
+public class ChangeLogReport
+    extends AbstractMavenReport
+{
+    /**
+     * Used to specify whether to build the log from a range, absolute date.
+     *
+     * @parameter
+     */
+    private String type = "range";
+
+    /**
+     * Used to specify the number of days of log entries to retrieve.
+     *
+     * @parameter
+     */
+    private int range = -1;
+
+    /**
+     * Used to specify the absolute date (or list of dates) to start log entries from.
+     *
+     * @parameter
+     */
+    private List dates;
+
+    /**
+     * Used to specify the tag (or list of tags) to start log entries from.
+     *
+     * @parameter
+     */
+    private List tags;
+
+    /**
+     * Used to specify the date format of log entries to retrieve.
+     *
+     * @parameter
+     */
+    private String dateFormat = "yyyy-MM-dd";
+
+    /**
+     * Input dir.  Directory where the sources are located.
+     *
+     * @parameter expression="${project.build.sourceDirectory}"
+     * @required
+     */
+    private File basedir;
+
+    /**
+     * Output file for xml document
+     *
+     * @parameter expression="${project.build.directory}/changelog.xml"
+     * @required
+     */
+    private File outputXML;
+
+    /**
+     * Allows the user to make changelog regenerate the changelog.xml file for the specified time in minutes.
+     *
+     * @parameter expression="${outputXMLExpiration}" default-value="60"
+     * @required
+     */
+    private int outputXMLExpiration;
+
+    /**
+     * Comment format string used for interrogating
+     * the revision control system.
+     * Currently only used by the ClearcaseChangeLogGenerator.
+     */
+    private String commentFormat;
+
+    /**
+     * Output encoding for the xml document
+     *
+     * @parameter
+     */
+    private String outputEncoding = "ISO-8859-1";
+
+    /**
+     * The user name (used by svn and starteam protocol).
+     *
+     * @parameter expression="${username}"
+     */
+    private String username;
+
+    /**
+     * The user password (used by svn and starteam protocol).
+     *
+     * @parameter expression="${password}"
+     */
+    private String password;
+
+    /**
+     * The private key (used by java svn).
+     *
+     * @parameter expression="${privateKey}"
+     */
+    private String privateKey;
+
+    /**
+     * The passphrase (used by java svn).
+     *
+     * @parameter expression="${passphrase}"
+     */
+    private String passphrase;
+
+    /**
+     * The url of tags base directory (used by svn protocol).
+     *
+     * @parameter expression="${tagBase}"
+     */
+    private String tagBase;
+
+    /**
+     * The URL to view the scm. Basis for external links from the generated report.
+     *
+     * @parameter expression="${project.scm.url}"
+     */
+    private String scmUrl;
+
+    /**
+     * The Maven Project Object
+     *
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * The directory where the report will be generated
+     *
+     * @parameter expression="${project.build.directory}/site"
+     * @required
+     * @readonly
+     */
+    private File outputDirectory;
+
+    /**
+     * @parameter expression="${component.org.codehaus.doxia.site.renderer.SiteRenderer}"
+     * @required
+     * @readonly
+     */
+    private SiteRenderer siteRenderer;
+
+    /**
+     * @parameter expression="${settings.offline}"
+     * @required
+     * @readonly
+     */
+    private boolean offline;
+
+    /**
+     * @parameter expression="${component.org.apache.maven.scm.manager.ScmManager}"
+     * @required
+     * @readonly
+     */
+    private ScmManager manager;
+
+    /**
+     * @parameter expression="${settings}"
+     * @required
+     * @readonly
+     */
+    private Settings settings;
+
+    /**
+     * Allows the user to choose which scm connection to use when connecting to the scm.
+     * Can either be "connection" or "developerConnection"
+     *
+     * @parameter default-value="connection"
+     * @required
+     */
+    private String connectionType;
+
+    /**
+     * Allows the user to specify the file detail URL to use when viewing an scm file.
+     *
+     * @parameter expression="${project.scm.url}"
+     */
+    private String displayFileDetailUrl;
+
+    // temporary field holder while generating the report
+    private String rpt_Repository, rpt_OneRepoParam, rpt_MultiRepoParam;
+
+    // field for SCM Connection URL
+    private String connection;
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#executeReport(java.util.Locale)
+     */
+    public void executeReport( Locale locale )
+        throws MavenReportException
+    {
+        //check if sources exists <-- required for parent poms
+        if ( !basedir.exists() )
+        {
+            doGenerateEmptyReport( getBundle( locale ), getSink() );
+
+            return;
+        }
+
+        verifySCMTypeParams();
+
+        doGenerateReport( getChangedSets(), getBundle( locale ), getSink() );
+    }
+
+    /**
+     * populates the changedSets field by either connecting to the SCM or using an existing XML generated in a previous
+     * run of the report
+     *
+     * @throws MavenReportException
+     */
+    protected List getChangedSets()
+        throws MavenReportException
+    {
+        List changelogList = null;
+
+        if ( outputXML.exists() )
+        {
+            if ( outputXMLExpiration * 60000 > System.currentTimeMillis() - outputXML.lastModified() )
+            {
+                try
+                {
+                    FileInputStream fIn = new FileInputStream( outputXML );
+
+                    getLog().info( "Using existing changelog.xml..." );
+
+                    changelogList = ChangeLog.loadChangedSets( fIn );
+                }
+                catch ( FileNotFoundException e )
+                {
+                    //do nothing, just regenerate
+                }
+                catch ( Exception e )
+                {
+                    throw new MavenReportException( "An error occurred while parsing " + outputXML.getAbsolutePath(),
+                                                    e );
+                }
+            }
+        }
+
+        if ( changelogList == null )
+        {
+            if ( offline )
+            {
+                throw new MavenReportException( "This report requires online mode." );
+            }
+
+            getLog().info( "Generating changed sets xml to: " + outputXML.getAbsolutePath() );
+
+            changelogList = generateChangeSetsFromSCM();
+
+            try
+            {
+                writeChangelogXml( changelogList );
+            }
+            catch ( FileNotFoundException e )
+            {
+                throw new MavenReportException( "Can't create " + outputXML.getAbsolutePath(), e );
+            }
+        }
+
+        return changelogList;
+    }
+
+    private void writeChangelogXml( List changelogList )
+        throws FileNotFoundException
+    {
+        StringBuffer changelogXml = new StringBuffer();
+
+        changelogXml.append( "<?xml version=\"1.0\" encoding=\"" ).append( outputEncoding ).append( "\"?>\n" );
+        changelogXml.append( "<changelog>" );
+
+        for ( Iterator sets = changelogList.iterator(); sets.hasNext(); )
+        {
+            changelogXml.append( "\n  " );
+
+            ChangeLogSet changelogSet = (ChangeLogSet) sets.next();
+            String changeset = changelogSet.toXML( outputEncoding );
+
+            //remove xml header
+            if ( changeset.startsWith( "<?xml" ) )
+            {
+                int idx = changeset.indexOf( "?>" ) + 2;
+                changeset = changeset.substring( idx );
+            }
+
+            changelogXml.append( changeset );
+        }
+
+        changelogXml.append( "\n</changelog>" );
+
+        outputXML.getParentFile().mkdirs();
+
+        PrintWriter pw = new PrintWriter( new BufferedOutputStream( new FileOutputStream( outputXML ) ) );
+        pw.write( changelogXml.toString() );
+        pw.flush();
+        pw.close();
+    }
+
+    /**
+     * creates a ChangeLog object and then connects to the SCM to generate the changed sets
+     *
+     * @return changedlogsets generated from the SCM
+     * @throws MavenReportException
+     */
+    protected List generateChangeSetsFromSCM()
+        throws MavenReportException
+    {
+        try
+        {
+            List changeSets = new ArrayList();
+
+            ScmRepository repository = getScmRepository();
+
+            ScmProvider provider = manager.getProviderByRepository( repository );
+
+            ChangeLogScmResult result;
+
+            if ( "range".equals( type ) )
+            {
+                result =
+                    provider.changeLog( repository, new ScmFileSet( basedir ), null, null, range, null, dateFormat );
+
+                checkResult( result );
+
+                changeSets.add( result.getChangeLog() );
+            }
+            else if ( "tag".equals( type ) )
+            {
+                Iterator tagsIter = tags.iterator();
+
+                String startTag = (String) tagsIter.next();
+                String endTag = null;
+
+                if ( tagsIter.hasNext() )
+                {
+                    while ( tagsIter.hasNext() )
+                    {
+                        endTag = (String) tagsIter.next();
+
+                        result = provider.changeLog( repository, new ScmFileSet( basedir ), startTag, endTag );
+
+                        checkResult( result );
+
+                        changeSets.add( result.getChangeLog() );
+
+                        startTag = endTag;
+                    }
+                }
+                else
+                {
+                    result = provider.changeLog( repository, new ScmFileSet( basedir ), startTag, endTag );
+
+                    checkResult( result );
+
+                    changeSets.add( result.getChangeLog() );
+                }
+            }
+            else if ( "date".equals( type ) )
+            {
+                Iterator dateIter = dates.iterator();
+
+                String startDate = (String) dateIter.next();
+                String endDate = null;
+
+                if ( dateIter.hasNext() )
+                {
+                    while ( dateIter.hasNext() )
+                    {
+                        endDate = (String) dateIter.next();
+
+                        result = provider.changeLog( repository, new ScmFileSet( basedir ), parseDate( startDate ),
+                                                     parseDate( endDate ), 0, null );
+
+                        checkResult( result );
+
+                        changeSets.add( result.getChangeLog() );
+
+                        startDate = endDate;
+                    }
+                }
+                else
+                {
+                    result = provider.changeLog( repository, new ScmFileSet( basedir ), parseDate( startDate ),
+                                                 parseDate( endDate ), 0, null );
+
+                    checkResult( result );
+
+                    changeSets.add( result.getChangeLog() );
+                }
+            }
+            else
+            {
+                throw new MavenReportException( "The type'" + type + "' isn't supported." );
+            }
+
+            return changeSets;
+        }
+        catch ( ScmException e )
+        {
+            throw new MavenReportException( "Cannot run changelog command : ", e );
+        }
+        catch ( MojoExecutionException e )
+        {
+            throw new MavenReportException( "An erro is occurred durint changelog command : ", e );
+        }
+    }
+
+    /**
+     * Converts the localized date string pattern to date object.
+     *
+     * @return A date
+     */
+    private Date parseDate( String date )
+        throws MojoExecutionException
+    {
+        if ( date == null || date.trim().length() == 0 )
+        {
+            return null;
+        }
+
+        SimpleDateFormat formatter = new SimpleDateFormat( "yyyy-MM-dd" );
+
+        try
+        {
+            return formatter.parse( date );
+        }
+        catch ( ParseException e )
+        {
+            throw new MojoExecutionException( "Please use this date pattern: " + formatter.toLocalizedPattern(), e );
+        }
+    }
+
+    public ScmRepository getScmRepository()
+        throws ScmException
+    {
+        ScmRepository repository;
+
+        try
+        {
+            repository = manager.makeScmRepository( getConnection() );
+
+            ScmProviderRepository providerRepo = repository.getProviderRepository();
+
+            if ( !StringUtils.isEmpty( username ) )
+            {
+                providerRepo.setUser( username );
+            }
+
+            if ( !StringUtils.isEmpty( password ) )
+            {
+                providerRepo.setPassword( password );
+            }
+
+            if ( repository.getProviderRepository() instanceof ScmProviderRepositoryWithHost )
+            {
+                ScmProviderRepositoryWithHost repo = (ScmProviderRepositoryWithHost) repository.getProviderRepository();
+
+                loadInfosFromSettings( repo );
+
+                if ( !StringUtils.isEmpty( username ) )
+                {
+                    repo.setUser( username );
+                }
+
+                if ( !StringUtils.isEmpty( password ) )
+                {
+                    repo.setPassword( password );
+                }
+
+                if ( !StringUtils.isEmpty( privateKey ) )
+                {
+                    repo.setPrivateKey( privateKey );
+                }
+
+                if ( !StringUtils.isEmpty( passphrase ) )
+                {
+                    repo.setPassphrase( passphrase );
+                }
+            }
+
+            if ( !StringUtils.isEmpty( tagBase ) && repository.getProvider().equals( "svn" ) )
+            {
+                SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) repository.getProviderRepository();
+
+                svnRepo.setTagBase( tagBase );
+            }
+        }
+        catch ( Exception e )
+        {
+            throw new ScmException( "Can't load the scm provider.", e );
+        }
+
+        return repository;
+    }
+
+    /**
+     * Load username password from settings if user has not set them in JVM properties
+     *
+     * @param repo
+     */
+    private void loadInfosFromSettings( ScmProviderRepositoryWithHost repo )
+    {
+        if ( username == null || password == null )
+        {
+            String host = repo.getHost();
+
+            int port = repo.getPort();
+
+            if ( port > 0 )
+            {
+                host += ":" + port;
+            }
+
+            Server server = this.settings.getServer( host );
+
+            if ( server != null )
+            {
+                if ( username == null )
+                {
+                    username = this.settings.getServer( host ).getUsername();
+                }
+
+                if ( password == null )
+                {
+                    password = this.settings.getServer( host ).getPassword();
+                }
+
+                if ( privateKey == null )
+                {
+                    privateKey = this.settings.getServer( host ).getPrivateKey();
+                }
+
+                if ( passphrase == null )
+                {
+                    passphrase = this.settings.getServer( host ).getPassphrase();
+                }
+            }
+        }
+    }
+
+    public void checkResult( ScmResult result )
+        throws MojoExecutionException
+    {
+        if ( !result.isSuccess() )
+        {
+            getLog().error( "Provider message:" );
+
+            getLog().error( result.getProviderMessage() == null ? "" : result.getProviderMessage() );
+
+            getLog().error( "Command output:" );
+
+            getLog().error( result.getCommandOutput() == null ? "" : result.getCommandOutput() );
+
+            throw new MojoExecutionException( "Command failed." );
+        }
+    }
+
+    /**
+     * used to retrieve the SCM connection string
+     *
+     * @return the url string used to connect to the SCM
+     * @throws MavenReportException when there is insufficient information to retrieve the SCM connection string
+     */
+    protected String getConnection()
+        throws MavenReportException
+    {
+        if ( this.connection != null )
+        {
+            return connection;
+        }
+
+        if ( project.getScm() == null )
+        {
+            throw new MavenReportException( "SCM Connection is not set." );
+        }
+
+        String scmConnection = project.getScm().getConnection();
+        if ( StringUtils.isNotEmpty( scmConnection ) && "connection".equals( connectionType.toLowerCase() ) )
+        {
+            connection = scmConnection;
+        }
+
+        String scmDeveloper = project.getScm().getDeveloperConnection();
+        if ( StringUtils.isNotEmpty( scmDeveloper ) && "developerconnection".equals( connectionType.toLowerCase() ) )
+        {
+            connection = scmDeveloper;
+        }
+
+        if ( StringUtils.isEmpty( connection ) )
+        {
+            throw new MavenReportException( "SCM Connection is not set." );
+        }
+
+        return connection;
+    }
+
+    /**
+     * checks whether there are enough configuration parameters to generate the report
+     *
+     * @throws MavenReportException when there is insufficient paramters to generate the report
+     */
+    private void verifySCMTypeParams()
+        throws MavenReportException
+    {
+        if ( "range".equals( type ) )
+        {
+            if ( range == -1 )
+            {
+                range = 30;
+            }
+        }
+        else if ( "date".equals( type ) )
+        {
+            if ( dates == null )
+            {
+                throw new MavenReportException(
+                    "The dates parameter is required when type=\"date\". The value should be the absolute date for the start of the log." );
+            }
+        }
+        else if ( "tag".equals( type ) )
+        {
+            if ( tags == null )
+            {
+                throw new MavenReportException( "The tags parameter is required when type=\"tag\"." );
+            }
+        }
+        else
+        {
+            throw new MavenReportException( "The type parameter has an invalid value: " + type +
+                ".  The value should be \"range\", \"date\", or \"tag\"." );
+        }
+    }
+
+    /**
+     * generates an empty report in case there are no sources to generate a report with
+     *
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    protected void doGenerateEmptyReport( ResourceBundle bundle, Sink sink )
+    {
+        sink.head();
+        sink.title();
+        sink.text( bundle.getString( "report.changelog.header" ) );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+        sink.section1();
+
+        sink.sectionTitle1();
+        sink.text( bundle.getString( "report.changelog.mainTitle" ) );
+        sink.sectionTitle1_();
+
+        sink.paragraph();
+        sink.text( "No sources found to create a report." );
+        sink.paragraph_();
+
+        sink.section1_();
+
+        sink.body_();
+        sink.flush();
+        sink.close();
+    }
+
+    /**
+     * method that generates the report for this mojo. This method is overridden by dev-activity and file-activity mojo
+     *
+     * @param changeLogSets changed sets to generate the report from
+     * @param bundle        the resource bundle to retrieve report phrases from
+     * @param sink          the report formatting tool
+     */
+    protected void doGenerateReport( List changeLogSets, ResourceBundle bundle, Sink sink )
+    {
+        sink.head();
+        sink.title();
+        sink.text( bundle.getString( "report.changelog.header" ) );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+        sink.section1();
+
+        sink.sectionTitle1();
+        sink.text( bundle.getString( "report.changelog.mainTitle" ) );
+        sink.sectionTitle1_();
+
+        // Summary section
+        doSummarySection( changeLogSets, bundle, sink );
+
+        for ( Iterator sets = changeLogSets.iterator(); sets.hasNext(); )
+        {
+            ChangeLogSet changeLogSet = (ChangeLogSet) sets.next();
+
+            doChangedSet( changeLogSet, bundle, sink );
+        }
+
+        sink.section1_();
+        sink.body_();
+
+        sink.flush();
+        sink.close();
+    }
+
+    /**
+     * generates the report summary section of the report
+     *
+     * @param changeLogSets changed sets to generate the report from
+     * @param bundle        the resource bundle to retrieve report phrases from
+     * @param sink          the report formatting tool
+     */
+    private void doSummarySection( List changeLogSets, ResourceBundle bundle, Sink sink )
+    {
+        sink.paragraph();
+
+        sink.text( bundle.getString( "report.changelog.ChangedSetsTotal" ) );
+        sink.text( ": " + changeLogSets.size() );
+
+        sink.paragraph_();
+    }
+
+    /**
+     * generates a section of the report referring to a changeset
+     *
+     * @param set    the current ChangeSet to generate this section of the report
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    private void doChangedSet( ChangeLogSet set, ResourceBundle bundle, Sink sink )
+    {
+        sink.section1();
+
+        sink.sectionTitle2();
+        if ( set.getStartDate() == null )
+        {
+            sink.text( bundle.getString( "report.SetRangeUnknown" ) );
+        }
+        else if ( set.getEndDate() == null )
+        {
+            sink.text( bundle.getString( "report.SetRangeSince" ) );
+            sink.text( " " + set.getStartDate() );
+        }
+        else
+        {
+            sink.text( bundle.getString( "report.SetRangeBetween" ) );
+            sink.text( " " + set.getStartDate() + " " + bundle.getString( "report.To" ) + " " + set.getEndDate() );
+        }
+        sink.sectionTitle2_();
+
+        sink.paragraph();
+        sink.text( bundle.getString( "report.TotalCommits" ) );
+        sink.text( ": " + set.getChangeSets().size() );
+        sink.lineBreak();
+        sink.text( bundle.getString( "report.changelog.FilesChanged" ) );
+        sink.text( ": " + countFilesChanged( set.getChangeSets() ) );
+        sink.paragraph_();
+
+        doChangedSetTable( set.getChangeSets(), bundle, sink );
+
+        sink.section1_();
+    }
+
+    /**
+     * counts the number of files that were changed in the specified SCM
+     *
+     * @param entries a collection of SCM changes
+     * @return number of files changed for the changedsets
+     */
+    protected long countFilesChanged( Collection entries )
+    {
+        if ( entries == null )
+        {
+            return 0;
+        }
+
+        if ( entries.isEmpty() )
+        {
+            return 0;
+        }
+
+        HashMap fileList = new HashMap();
+
+        for ( Iterator i = entries.iterator(); i.hasNext(); )
+        {
+            ChangeSet entry = (ChangeSet) i.next();
+
+            List files = entry.getFiles();
+
+            for ( Iterator fileIterator = files.iterator(); fileIterator.hasNext(); )
+            {
+                ChangeFile file = (ChangeFile) fileIterator.next();
+
+                String name = file.getName();
+
+                if ( fileList.containsKey( name ) )
+                {
+                    LinkedList list = (LinkedList) fileList.get( name );
+
+                    list.add( file );
+                }
+                else
+                {
+                    LinkedList list = new LinkedList();
+
+                    list.add( file );
+
+                    fileList.put( name, list );
+                }
+            }
+        }
+
+        return fileList.size();
+    }
+
+    /**
+     * generates the report table showing the SCM log entries
+     *
+     * @param entries a list of change log entries to generate the report from
+     * @param bundle  the resource bundle to retrieve report phrases from
+     * @param sink    the report formatting tool
+     */
+    private void doChangedSetTable( Collection entries, ResourceBundle bundle, Sink sink )
+    {
+        sink.table();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.changelog.timestamp" ) );
+        sink.tableHeaderCell_();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.changelog.author" ) );
+        sink.tableHeaderCell_();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.changelog.details" ) );
+        sink.tableHeaderCell_();
+        sink.tableRow_();
+
+        for ( Iterator i = entries.iterator(); i.hasNext(); )
+        {
+            ChangeSet entry = (ChangeSet) i.next();
+
+            doChangedSetDetail( entry, bundle, sink );
+        }
+
+        sink.table_();
+    }
+
+    /**
+     * reports on the details of an SCM entry log
+     *
+     * @param entry  an SCM entry to generate the report from
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    private void doChangedSetDetail( ChangeSet entry, ResourceBundle bundle, Sink sink )
+    {
+        sink.tableRow();
+
+        sink.tableCell();
+        sink.text( entry.getDateFormatted() + " " + entry.getTimeFormatted() );
+        sink.tableCell_();
+
+        sink.tableCell();
+        sink.text( entry.getAuthor() );
+        sink.tableCell_();
+
+        sink.tableCell();
+        initReportUrls();
+        //doRevision( entry.getFiles(), bundle, sink );
+        doChangedFiles( entry.getFiles(), sink );
+        sink.lineBreak();
+        sink.text( entry.getComment() );
+        sink.tableCell_();
+
+        sink.tableRow_();
+    }
+
+    /**
+     * populates the report url used to create links from certain elements of the report
+     */
+    protected void initReportUrls()
+    {
+        if ( scmUrl != null )
+        {
+            int idx = scmUrl.indexOf( '?' );
+
+            if ( idx > 0 )
+            {
+                rpt_Repository = scmUrl.substring( 0, idx );
+
+                if ( scmUrl.equals( displayFileDetailUrl ) )
+                {
+                    String rpt_TmpMultiRepoParam = scmUrl.substring( rpt_Repository.length() );
+
+                    rpt_OneRepoParam = "?" + rpt_TmpMultiRepoParam.substring( 1 );
+
+                    rpt_MultiRepoParam = "&" + rpt_TmpMultiRepoParam.substring( 1 );
+                }
+                else
+                {
+                    idx = displayFileDetailUrl.indexOf( "?" );
+
+                    if ( idx > 0 )
+                    {
+                        displayFileDetailUrl = displayFileDetailUrl.substring( 0, idx );
+
+                        String rpt_TmpMultiRepoParam = displayFileDetailUrl.substring( idx + 1 );
+
+                        rpt_OneRepoParam = "?" + rpt_TmpMultiRepoParam;
+
+                        rpt_MultiRepoParam = "&" + rpt_TmpMultiRepoParam;
+                    }
+                    else
+                    {
+                        rpt_OneRepoParam = "";
+
+                        rpt_MultiRepoParam = "";
+                    }
+                }
+            }
+            else
+            {
+                rpt_Repository = scmUrl;
+
+                rpt_OneRepoParam = "";
+
+                rpt_MultiRepoParam = "";
+            }
+        }
+    }
+
+    /**
+     * generates the section of the report listing all the files revisions
+     *
+     * @param files list of files to generate the reports from
+     */
+    private void doChangedFiles( List files, Sink sink )
+    {
+        for ( Iterator i = files.iterator(); i.hasNext(); )
+        {
+            ChangeFile file = (ChangeFile) i.next();
+            sinkLogFile( sink, file.getName(), file.getRevision() );
+        }
+    }
+
+    /**
+     * generates the section of the report detailing the revisions made and the files changed
+     *
+     * @param sink     the report formatting tool
+     * @param name     filename of the changed file
+     * @param revision the revision code for this file
+     */
+    private void sinkLogFile( Sink sink, String name, String revision )
+    {
+        sink.paragraph();
+
+        try
+        {
+            String connection = getConnection();
+
+            generateLinks( connection, name, revision, sink );
+        }
+        catch ( Exception e )
+        {
+            getLog().debug( e );
+
+            sink.text( name + " v " + revision );
+        }
+
+        sink.paragraph_();
+    }
+
+    /**
+     * attaches the http links from the changed files
+     *
+     * @param connection the string used to connect to the SCM
+     * @param name       filename of the file that was changed
+     * @param sink       the report formatting tool
+     */
+    protected void generateLinks( String connection, String name, Sink sink )
+    {
+        generateLinks( connection, name, null, sink );
+    }
+
+    /**
+     * attaches the http links from the changed files
+     *
+     * @param connection the string used to connect to the SCM
+     * @param name       filename of the file that was changed
+     * @param revision   the revision code
+     * @param sink       the report formatting tool
+     */
+    protected void generateLinks( String connection, String name, String revision, Sink sink )
+    {
+        String linkFile = null;
+        String linkRev = null;
+
+        if ( displayFileDetailUrl != null )
+        {
+            if ( connection.startsWith( "scm:perforce" ) )
+            {
+                String path = getAbsolutePath( displayFileDetailUrl, name );
+                linkFile = path + "?ac=22";
+                if ( revision != null )
+                {
+                    linkRev = path + "?ac=64&rev=" + revision;
+                }
+            }
+            else if ( connection.startsWith( "scm:clearcase" ) )
+            {
+                String path = getAbsolutePath( displayFileDetailUrl, name );
+                linkFile = path + rpt_OneRepoParam;
+            }
+            else if ( connection.indexOf( "cvsmonitor.pl" ) > 0 )
+            {
+                String module = rpt_OneRepoParam.replaceAll( "^.*(&amp;module=.*?(?:&amp;|$)).*$", "$1" );
+                linkFile = displayFileDetailUrl + "?cmd=viewBrowseFile" + module + "&file=" + name;
+                if ( revision != null )
+                {
+                    linkRev =
+                        rpt_Repository + "?cmd=viewBrowseVersion" + module + "&file=" + name + "&version=" + revision;
+                }
+            }
+            else
+            {
+                String path = getAbsolutePath( displayFileDetailUrl, name );
+                linkFile = path + rpt_OneRepoParam;
+                if ( revision != null )
+                {
+                    linkRev = path + "?rev=" + revision + "&content-type=text/vnd.viewcvs-markup" + rpt_MultiRepoParam;
+                }
+            }
+        }
+
+        if ( linkFile != null )
+        {
+            sink.link( linkFile );
+            sink.text( name );
+            sink.link_();
+        }
+        else
+        {
+            sink.text( name );
+        }
+
+        sink.text( " " );
+
+        if ( linkRev != null )
+        {
+            sink.link( linkRev );
+            sink.text( "v " + revision );
+            sink.link_();
+        }
+        else if ( revision != null )
+        {
+            sink.text( "v " + revision );
+        }
+    }
+
+    /**
+     * calculates the path from a base directory to a target file
+     *
+     * @param base   base directory to create the absolute path from
+     * @param target target file to create the absolute path to
+     */
+    private String getAbsolutePath( final String base, final String target )
+    {
+        String absPath = "";
+
+        StringTokenizer baseTokens = new StringTokenizer( base.replaceAll( "\\\\", "/" ), "/", true );
+
+        StringTokenizer targetTokens = new StringTokenizer( target.replaceAll( "\\\\", "/" ), "/" );
+
+        String targetRoot = targetTokens.nextToken();
+
+        while ( baseTokens.hasMoreTokens() )
+        {
+            String baseToken = baseTokens.nextToken();
+
+            if ( baseToken.equals( targetRoot ) )
+            {
+                break;
+            }
+
+            absPath += baseToken;
+        }
+
+        return absPath + target.substring( 1 );
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#getProject()
+     */
+    protected MavenProject getProject()
+    {
+        return project;
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#getOutputDirectory()
+     */
+    protected String getOutputDirectory()
+    {
+        return outputDirectory.getAbsolutePath();
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer()
+     */
+    protected SiteRenderer getSiteRenderer()
+    {
+        return siteRenderer;
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
+     */
+    public String getDescription( Locale locale )
+    {
+        return "Generated Changelog report from SCM";
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
+     */
+    public String getName( Locale locale )
+    {
+        return "changelog";
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getOutputName()
+     */
+    public String getOutputName()
+    {
+        return "changelog";
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getOutputName()
+     */
+    protected ResourceBundle getBundle( Locale locale )
+    {
+        return ResourceBundle.getBundle( "scm-activity", locale, this.getClass().getClassLoader() );
+    }
+
+    public boolean canGenerateReport()
+    {
+        if ( offline && !outputXML.exists() )
+        {
+            return false;
+        }
+        else
+        {
+            return true;
+        }
+    }
+}

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogReport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/ChangeLogReport.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/DeveloperActivityReport.java
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/DeveloperActivityReport.java?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/DeveloperActivityReport.java (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/DeveloperActivityReport.java Tue Mar 21 22:02:52 2006
@@ -0,0 +1,393 @@
+package org.apache.maven.changelog;
+
+/*
+* Copyright 2001-2006 The Apache Software Foundation.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+import org.apache.maven.model.Developer;
+import org.apache.maven.scm.ChangeFile;
+import org.apache.maven.scm.ChangeSet;
+import org.apache.maven.scm.command.changelog.ChangeLogSet;
+import org.codehaus.doxia.sink.Sink;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+
+/**
+ * @goal dev-activity
+ * @description A Maven 2.0 developer activity report plugin
+ */
+public class DeveloperActivityReport
+    extends ChangeLogReport
+{
+    /**
+     * List of developers to be shown on the report.
+     *
+     * @parameter expression="${project.developers}"
+     */
+    private List developers;
+
+    /**
+     * Used to hold data while creating the report
+     */
+    private HashMap commits;
+
+    private HashMap files;
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
+     */
+    public String getDescription( Locale locale )
+    {
+        return "Generated developer activity report from SCM";
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
+     */
+    public String getName( Locale locale )
+    {
+        return "dev-activity";
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getOutputName()
+     */
+    public String getOutputName()
+    {
+        return "dev-activity";
+    }
+
+    /**
+     * generates an empty report in case there are no sources to generate a report with
+     *
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    protected void doGenerateEmptyReport( ResourceBundle bundle, Sink sink )
+    {
+        sink.head();
+        sink.title();
+        sink.text( bundle.getString( "report.dev-activity.header" ) );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+        sink.section1();
+
+        sink.sectionTitle1();
+        sink.text( bundle.getString( "report.dev-activity.mainTitle" ) );
+        sink.sectionTitle1_();
+
+        sink.paragraph();
+        sink.text( "No sources found to create a report." );
+        sink.paragraph_();
+
+        sink.section1_();
+
+        sink.body_();
+        sink.flush();
+        sink.close();
+    }
+
+    /**
+     * method that generates the report for this mojo.
+     *
+     * @param changeLogSets changed sets to generate the report from
+     * @param bundle        the resource bundle to retrieve report phrases from
+     * @param sink          the report formatting tool
+     */
+    protected void doGenerateReport( ChangeLogSet changeLogSets, ResourceBundle bundle, Sink sink )
+    {
+        sink.head();
+        sink.title();
+        sink.text( bundle.getString( "report.dev-activity.header" ) );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+        sink.section1();
+        sink.sectionTitle1();
+        sink.text( bundle.getString( "report.dev-activity.mainTitle" ) );
+        sink.sectionTitle1_();
+
+        doChangedSets( changeLogSets, bundle, sink );
+
+        sink.section1_();
+        sink.body_();
+        sink.flush();
+        sink.table_();
+    }
+
+    /**
+     * generates a section of the report referring to a changeset
+     *
+     * @param set    the current ChangeSet to generate this section of the report
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    private void doChangedSets( ChangeLogSet set, ResourceBundle bundle, Sink sink )
+    {
+        sink.section2();
+        sink.sectionTitle2();
+        if ( set.getStartDate() == null )
+        {
+            sink.text( bundle.getString( "report.SetRangeUnknown" ) );
+        }
+        else if ( set.getEndDate() == null )
+        {
+            sink.text( bundle.getString( "report.SetRangeSince" ) );
+        }
+        else
+        {
+            sink.text( " " + set.getStartDate() + " " + bundle.getString( "report.To" ) + " " + set.getEndDate() );
+            sink.sectionTitle2_();
+        }
+        doSummary( set, bundle, sink );
+
+        sink.table();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.dev-activity.developer" ) );
+        sink.tableHeaderCell_();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.TotalCommits" ) );
+        sink.tableHeaderCell_();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.dev-activity.filesChanged" ) );
+        sink.tableHeaderCell_();
+        sink.tableRow_();
+
+        doDeveloperRows( set, sink );
+
+        sink.table_();
+
+        sink.section2_();
+    }
+
+    /**
+     * generates the report summary section of the report
+     *
+     * @param set    changed set to generate the report from
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    private void doSummary( ChangeLogSet set, ResourceBundle bundle, Sink sink )
+    {
+        sink.paragraph();
+
+        sink.text( bundle.getString( "report.dev-activity.range" ) );
+        sink.text( ": " + set.getStartDate() + " " + bundle.getString( "report.To" ) + " " + set.getEndDate() );
+
+        sink.text( ", " + bundle.getString( "report.TotalCommits" ) );
+        sink.text( ":" + set.getChangeSets().size() );
+
+        sink.text( ", " + bundle.getString( "report.dev-activity.filesChanged" ) );
+        sink.text( ":" + countFilesChanged( set.getChangeSets() ) );
+
+        sink.paragraph_();
+    }
+
+    /**
+     * counts the total commits made to the given sets
+     *
+     * @param sets collection of sets to count all the commits
+     * @return total number of commits for the given sets
+     */
+    private long getCommits( Collection sets )
+    {
+        long commits = 0;
+
+        for ( Iterator i = sets.iterator(); i.hasNext(); )
+        {
+            ChangeLogSet set = (ChangeLogSet) i.next();
+
+            commits += set.getChangeSets().size();
+        }
+
+        return commits;
+    }
+
+    /**
+     * counts the total number of files changed
+     *
+     * @param sets collection of sets to count all the files changed
+     * @return total number of files changed
+     */
+    private long getFilesChanged( Collection sets )
+    {
+        long count = 0;
+
+        for ( Iterator i = sets.iterator(); i.hasNext(); )
+        {
+            ChangeLogSet set = (ChangeLogSet) i.next();
+
+            count += countFilesChanged( set.getChangeSets() );
+        }
+
+        return count;
+    }
+
+    /**
+     * generates the report section table of the developers
+     *
+     * @param set  change log set generate the developer activity
+     * @param sink the report formatting tool
+     */
+    private void doDeveloperRows( ChangeLogSet set, Sink sink )
+    {
+        initDeveloperDetails( set );
+
+        //for( Iterator i=commits.keySet().iterator(); i.hasNext(); )
+        for ( Iterator i = developers.iterator(); i.hasNext(); )
+        {
+            Developer developer = (Developer) i.next();
+
+            String name = developer.getName();
+
+            String id = developer.getId();
+
+            LinkedList devCommits;
+            HashMap devFiles;
+
+            if ( !commits.containsKey( name ) )
+            {
+                if ( !commits.containsKey( id ) )
+                {
+                    continue;
+                }
+                else
+                {
+                    devCommits = (LinkedList) commits.get( id );
+
+                    devFiles = (HashMap) files.get( id );
+                }
+            }
+            else
+            {
+                devCommits = (LinkedList) commits.get( name );
+
+                devFiles = (HashMap) files.get( name );
+            }
+
+            sink.tableRow();
+
+            sink.tableCell();
+            sink.link( "team-list.html#" + developer.getId() );
+            sink.text( name );
+            sink.link_();
+            sink.tableCell_();
+
+            sink.tableCell();
+            sink.text( "" + devCommits.size() );
+            sink.tableCell_();
+
+            sink.tableCell();
+            sink.text( "" + devFiles.size() );
+            sink.tableCell_();
+
+            sink.tableRow_();
+        }
+    }
+
+    /**
+     * counts the number of commits and files changed for each developer
+     *
+     * @param set the change log set to generate the developer details from
+     */
+    private void initDeveloperDetails( ChangeLogSet set )
+    {
+        commits = new HashMap();
+
+        files = new HashMap();
+
+        countDevCommits( set.getChangeSets() );
+
+        countDevFiles( set.getChangeSets() );
+    }
+
+    /**
+     * counts the number of commits of each developer
+     *
+     * @param entries the change log entries used to search and count developer commits
+     */
+    private void countDevCommits( Collection entries )
+    {
+        for ( Iterator i = entries.iterator(); i.hasNext(); )
+        {
+            ChangeSet entry = (ChangeSet) i.next();
+
+            String developer = entry.getAuthor();
+
+            LinkedList list;
+
+            if ( commits.containsKey( developer ) )
+            {
+                list = (LinkedList) commits.get( developer );
+            }
+            else
+            {
+                list = new LinkedList();
+            }
+
+            list.add( entry );
+
+            commits.put( developer, list );
+        }
+    }
+
+    /**
+     * counts the number of files changed by each developer
+     *
+     * @param entries the change log entries used to search and count file changes
+     */
+    private void countDevFiles( Collection entries )
+    {
+        for ( Iterator i2 = entries.iterator(); i2.hasNext(); )
+        {
+            ChangeSet entry = (ChangeSet) i2.next();
+
+            String developer = entry.getAuthor();
+
+            HashMap filesMap;
+
+            if ( files.containsKey( developer ) )
+            {
+                filesMap = (HashMap) files.get( developer );
+            }
+            else
+            {
+                filesMap = new HashMap();
+            }
+
+            for ( Iterator i3 = entry.getFiles().iterator(); i3.hasNext(); )
+            {
+                ChangeFile file = (ChangeFile) i3.next();
+
+                filesMap.put( file.getName(), file );
+            }
+
+            files.put( developer, filesMap );
+        }
+    }
+}

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/DeveloperActivityReport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/DeveloperActivityReport.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityComparator.java
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityComparator.java?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityComparator.java (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityComparator.java Tue Mar 21 22:02:52 2006
@@ -0,0 +1,145 @@
+package org.apache.maven.changelog;
+
+/*
+ * Copyright 2001-2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.scm.ChangeFile;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+
+/**
+ * Object used to sort the file-activity report into descending order
+ */
+public class FileActivityComparator
+    implements Comparator
+{
+    /**
+     * @see java.util.Comparator#compare(Object,Object)
+     */
+    public int compare( Object o1, Object o2 )
+        throws ClassCastException
+    {
+        int returnValue;
+
+        LinkedList list1 = (LinkedList) o1;
+
+        LinkedList list2 = (LinkedList) o2;
+
+        returnValue = sortByCommits( list1, list2 );
+
+        if ( returnValue != 0 )
+        {
+            return returnValue;
+        }
+
+        returnValue = sortByRevision( list1, list2 );
+
+        if ( returnValue != 0 )
+        {
+            return returnValue;
+        }
+
+        returnValue = sortByName( list1, list2 );
+
+        return returnValue;
+    }
+
+    /**
+     * compares list1 and list2 by the number of commits
+     *
+     * @param list1 the first object in a compare statement
+     * @param list2 the object to compare list1 against
+     * @return an integer describing the order comparison of list1 and list2
+     */
+    private int sortByCommits( List list1, List list2 )
+    {
+        if ( list1.size() > list2.size() )
+        {
+            return -1;
+        }
+
+        if ( list1.size() < list2.size() )
+        {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    /**
+     * compares list1 and list2 by comparing their revision code
+     *
+     * @param list1 the first object in a compare statement
+     * @param list2 the object to compare list1 against
+     * @return an integer describing the order comparison of list1 and list2
+     */
+    private int sortByRevision( List list1, List list2 )
+    {
+        String revision1 = getLatestRevision( list1 );
+
+        String revision2 = getLatestRevision( list2 );
+
+        return revision1.compareTo( revision2 );
+    }
+
+    /**
+     * retrieves the latest revision from the commits made from the SCM
+     *
+     * @param list The list of revisions from the file
+     * @return the latest revision code
+     */
+    private String getLatestRevision( List list )
+    {
+        String latest = "";
+
+        for ( Iterator i = list.iterator(); i.hasNext(); )
+        {
+            ChangeFile file = (ChangeFile) i.next();
+
+            if ( latest.length() == 0 )
+            {
+                latest = file.getRevision();
+            }
+            else if ( latest.compareTo( file.getRevision() ) > 0 )
+            {
+                latest = file.getRevision();
+            }
+        }
+
+        return latest;
+    }
+
+    /**
+     * compares list1 and list2 by comparing their filenames. Least priority sorting when both number of commits and
+     * and revision are the same
+     *
+     * @param list1 the first object in a compare statement
+     * @param list2 the object to compare list1 against
+     * @return an integer describing the order comparison of list1 and list2
+     */
+    private int sortByName( List list1, List list2 )
+    {
+        ChangeFile file1 = (ChangeFile) list1.get( 0 );
+
+        ChangeFile file2 = (ChangeFile) list2.get( 0 );
+
+        return file1.getName().compareTo( file2.getName() );
+    }
+}
\ No newline at end of file

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityComparator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityComparator.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityReport.java
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityReport.java?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityReport.java (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityReport.java Tue Mar 21 22:02:52 2006
@@ -0,0 +1,279 @@
+package org.apache.maven.changelog;
+
+/*
+ * Copyright 2001-2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.scm.ChangeFile;
+import org.apache.maven.scm.ChangeSet;
+import org.apache.maven.scm.command.changelog.ChangeLogSet;
+import org.codehaus.doxia.sink.Sink;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * @goal file-activity
+ * @description A Maven 2.0 file activity report plugin
+ */
+public class FileActivityReport
+    extends ChangeLogReport
+{
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
+     */
+    public String getDescription( Locale locale )
+    {
+        return "Generate file activity report from SCM";
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
+     */
+    public String getName( Locale locale )
+    {
+        return "file-activity";
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getOutputName()
+     */
+    public String getOutputName()
+    {
+        return "file-activity";
+    }
+
+    /**
+     * generates an empty report in case there are no sources to generate a report with
+     *
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    protected void doGenerateEmptyReport( ResourceBundle bundle, Sink sink )
+    {
+        sink.head();
+        sink.title();
+        sink.text( bundle.getString( "report.file-activity.header" ) );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+        sink.section1();
+
+        sink.sectionTitle1();
+        sink.text( bundle.getString( "report.file-activity.mainTitle" ) );
+        sink.sectionTitle1_();
+
+        sink.paragraph();
+        sink.text( "No sources found to create a report." );
+        sink.paragraph_();
+
+        sink.section1_();
+
+        sink.body_();
+        sink.flush();
+        sink.close();
+    }
+
+    /**
+     * method that generates the report for this mojo.
+     *
+     * @param changeLogSets changed sets to generate the report from
+     * @param bundle        the resource bundle to retrieve report phrases from
+     * @param sink          the report formatting tool
+     */
+    protected void doGenerateReport( ChangeLogSet changeLogSets, ResourceBundle bundle, Sink sink )
+    {
+        sink.head();
+        sink.title();
+        sink.text( bundle.getString( "report.file-activity.header" ) );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+        sink.section1();
+        sink.sectionTitle1();
+        sink.text( bundle.getString( "report.file-activity.mainTitle" ) );
+        sink.sectionTitle1_();
+
+        doChangedSets( changeLogSets, bundle, sink );
+
+        sink.section1_();
+        sink.body_();
+
+        sink.table_();
+    }
+
+    /**
+     * generates a section of the report referring to a changeset
+     *
+     * @param set    the current ChangeSet to generate this section of the report
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    private void doChangedSets( ChangeLogSet set, ResourceBundle bundle, Sink sink )
+    {
+        sink.section2();
+        sink.sectionTitle2();
+        if ( set.getStartDate() == null )
+        {
+            sink.text( bundle.getString( "report.SetRangeUnknown" ) );
+        }
+        else if ( set.getEndDate() == null )
+        {
+            sink.text( bundle.getString( "report.SetRangeSince" ) );
+        }
+        else
+        {
+            sink.text( bundle.getString( "report.SetRangeBetween" ) );
+            sink.text( " " + set.getStartDate() + " " + bundle.getString( "report.To" ) + " " + set.getEndDate() );
+        }
+        sink.sectionTitle2_();
+
+        doSummary( set, bundle, sink );
+
+        sink.table();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.file-activity.filename" ) );
+        sink.tableHeaderCell_();
+        sink.tableHeaderCell();
+        sink.text( bundle.getString( "report.file-activity.timesChanged" ) );
+        sink.tableHeaderCell_();
+        sink.tableRow_();
+
+        doRows( set, sink );
+
+        sink.table_();
+
+        sink.section2_();
+    }
+
+    /**
+     * generates the report summary section of the report
+     *
+     * @param set    changed set to generate the report from
+     * @param bundle the resource bundle to retrieve report phrases from
+     * @param sink   the report formatting tool
+     */
+    private void doSummary( ChangeLogSet set, ResourceBundle bundle, Sink sink )
+    {
+        sink.paragraph();
+
+        sink.text( bundle.getString( "report.file-activity.range" ) );
+        sink.text( ": " + set.getStartDate() + " " + bundle.getString( "report.To" ) + " " + set.getEndDate() );
+
+        sink.text( ", " + bundle.getString( "report.TotalCommits" ) );
+        sink.text( ":" + set.getChangeSets().size() );
+
+        sink.text( ", " + bundle.getString( "report.file-activity.filesChanged" ) );
+        sink.text( ":" + countFilesChanged( set.getChangeSets() ) );
+
+        sink.paragraph_();
+    }
+
+    /**
+     * generates the row details for the file activity report
+     *
+     * @param set  the changelog set to generate a report with
+     * @param sink the report formatting tool
+     */
+    private void doRows( ChangeLogSet set, Sink sink )
+    {
+        List list = getOrderedFileList( set.getChangeSets() );
+
+        initReportUrls();
+
+        for ( Iterator i = list.iterator(); i.hasNext(); )
+        {
+            List revision = (List) i.next();
+            ChangeFile file = (ChangeFile) revision.get( 0 );
+
+            sink.tableRow();
+            sink.tableCell();
+
+            try
+            {
+                generateLinks( getConnection(), file.getName(), sink );
+            }
+            catch ( Exception e )
+            {
+                e.printStackTrace();
+
+                sink.text( file.getName() );
+            }
+            sink.tableCell_();
+
+            sink.tableCell();
+            sink.text( "" + revision.size() );
+
+            sink.tableCell_();
+            sink.tableRow_();
+        }
+    }
+
+    /**
+     * reads the change log entries and generates a list of files changed order by the number of times edited. This
+     * used the FileActivityComparator Object to sort the list
+     *
+     * @param entries the changelog entries to generate the report
+     * @return list of changed files within the SCM with the number of times changed in descending order
+     */
+    private List getOrderedFileList( Collection entries )
+    {
+        List list = new LinkedList();
+
+        Map map = new HashMap();
+
+        for ( Iterator i = entries.iterator(); i.hasNext(); )
+        {
+            ChangeSet entry = (ChangeSet) i.next();
+
+            for ( Iterator j = entry.getFiles().iterator(); j.hasNext(); )
+            {
+                ChangeFile file = (ChangeFile) j.next();
+
+                List revisions;
+
+                if ( map.containsKey( file.getName() ) )
+                {
+                    revisions = (List) map.get( file.getName() );
+                }
+                else
+                {
+                    revisions = new LinkedList();
+                }
+
+                revisions.add( file );
+
+                map.put( file.getName(), revisions );
+            }
+        }
+
+        list.addAll( map.values() );
+
+        Collections.sort( list, new FileActivityComparator() );
+
+        return list;
+    }
+}

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityReport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/java/org/apache/maven/changelog/FileActivityReport.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/scm-activity.properties
URL: http://svn.apache.org/viewcvs/maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/scm-activity.properties?rev=387745&view=auto
==============================================================================
--- maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/scm-activity.properties (added)
+++ maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/scm-activity.properties Tue Mar 21 22:02:52 2006
@@ -0,0 +1,31 @@
+#Commons
+report.SetRangeUnknown=Changes from an unknown range
+report.SetRangeSince=Changes since
+report.SetRangeBetween=Changes between
+report.To=to
+report.TotalCommits=Total commits
+
+#Changelog
+report.changelog.header=Change Log Report
+report.changelog.mainTitle=Change Log Report
+report.changelog.ChangedSetsTotal=Total number of changed sets
+report.changelog.FilesChanged=Total number of files changed
+report.changelog.timestamp=Timestamp
+report.changelog.author=Author
+report.changelog.details=Details
+report.changelog.revision=Revision
+
+#Developer Activity
+report.dev-activity.header=Developer Activity Report
+report.dev-activity.mainTitle=Developer Activity Report
+report.dev-activity.range=Range
+report.dev-activity.filesChanged=Total Number of Files Changed
+report.dev-activity.developer=Developer
+
+#File Activity
+report.file-activity.header=File Activity Report
+report.file-activity.mainTitle=File Activity Report
+report.file-activity.range=Range
+report.file-activity.filesChanged=Total Number of Files Changed
+report.file-activity.timesChanged=Number of Times Changed
+report.file-activity.filename=Filename
\ No newline at end of file

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/scm-activity.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/plugins/changelog-maven-plugin/src/main/resources/scm-activity.properties
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"