[MRM-123]

-generate/update rss feeds after repository scan
-add rss feed icon in repositories (for new artifacts in repo feed) and in browse artifact (for new versions of artifact feed)


git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@645576 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Maria Odea B. Ching 2008-04-07 15:50:57 +00:00
parent 5e407428a1
commit d346a91845
10 changed files with 138 additions and 46 deletions

View File

@ -48,6 +48,14 @@
<groupId>org.apache.archiva</groupId> <groupId>org.apache.archiva</groupId>
<artifactId>archiva-configuration</artifactId> <artifactId>archiva-configuration</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-rss</artifactId>
</dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-xml-tools</artifactId>
</dependency>
<dependency> <dependency>
<groupId>xmlunit</groupId> <groupId>xmlunit</groupId>
<artifactId>xmlunit</artifactId> <artifactId>xmlunit</artifactId>

View File

@ -23,13 +23,20 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.archiva.rss.processor.RssFeedProcessor;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.maven.archiva.configuration.FileTypes; import org.apache.maven.archiva.configuration.FileTypes;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.consumers.InvalidRepositoryContentConsumer; import org.apache.maven.archiva.consumers.InvalidRepositoryContentConsumer;
import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer; import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
import org.apache.maven.archiva.consumers.RepositoryContentConsumer; import org.apache.maven.archiva.consumers.RepositoryContentConsumer;
import org.apache.maven.archiva.model.ArchivaArtifact;
import org.apache.maven.archiva.model.ArtifactReference;
import org.apache.maven.archiva.repository.ManagedRepositoryContent;
import org.apache.maven.archiva.repository.RepositoryContentFactory;
import org.apache.maven.archiva.repository.RepositoryException; import org.apache.maven.archiva.repository.RepositoryException;
import org.apache.maven.archiva.repository.RepositoryNotFoundException;
import org.apache.maven.archiva.repository.layout.LayoutException;
import org.codehaus.plexus.util.DirectoryWalker; import org.codehaus.plexus.util.DirectoryWalker;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -55,6 +62,16 @@ public class DefaultRepositoryScanner
* @plexus.requirement * @plexus.requirement
*/ */
private RepositoryContentConsumers consumerUtil; private RepositoryContentConsumers consumerUtil;
/**
* @plexus.requirement
*/
private RepositoryContentFactory repositoryFactory;
/**
* @plexus.requirement role-hint="new-artifacts"
*/
private RssFeedProcessor rssFeedProcessor;
public RepositoryScanStatistics scan( ManagedRepositoryConfiguration repository, long changesSince ) public RepositoryScanStatistics scan( ManagedRepositoryConfiguration repository, long changesSince )
throws RepositoryException throws RepositoryException
@ -126,6 +143,10 @@ public class DefaultRepositoryScanner
stats.setKnownConsumers( gatherIds( knownContentConsumers ) ); stats.setKnownConsumers( gatherIds( knownContentConsumers ) );
stats.setInvalidConsumers( gatherIds( invalidContentConsumers ) ); stats.setInvalidConsumers( gatherIds( invalidContentConsumers ) );
// generate RSS feeds
List<ArchivaArtifact> newArtifacts = getNewArtifacts( scannerInstance.getNewFiles(), repository.getId() );
rssFeedProcessor.process( newArtifacts );
return stats; return stats;
} }
@ -138,4 +159,40 @@ public class DefaultRepositoryScanner
} }
return ids; return ids;
} }
private List<ArchivaArtifact> getNewArtifacts( List<File> files, String repoId )
{
List<ArchivaArtifact> newArtifacts = new ArrayList<ArchivaArtifact>();
// TODO: filter the file types of artifacts that will be included in the rss feeds
try
{
ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repoId );
for( File file : files )
{
try
{
ArtifactReference ref = repository.toArtifactReference( file.getAbsolutePath() );
ArchivaArtifact artifact = new ArchivaArtifact( ref.getGroupId(),ref.getArtifactId(), ref.getVersion(),
ref.getClassifier(), ref.getType() );
artifact.getModel().setRepositoryId( repoId );
newArtifacts.add( artifact );
}
catch ( LayoutException le )
{
}
}
}
catch ( RepositoryNotFoundException re )
{
log.error( re.getMessage() );
}
catch ( RepositoryException e )
{
log.error( e.getMessage() );
}
return newArtifacts;
}
} }

View File

@ -20,6 +20,7 @@ package org.apache.maven.archiva.repository.scanner;
*/ */
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.collections.Closure; import org.apache.commons.collections.Closure;
@ -66,6 +67,8 @@ public class RepositoryScannerInstance
private ConsumerProcessFileClosure consumerProcessFile; private ConsumerProcessFileClosure consumerProcessFile;
private ConsumerWantsFilePredicate consumerWantsFile; private ConsumerWantsFilePredicate consumerWantsFile;
private List<File> newFiles = new ArrayList<File>();
public RepositoryScannerInstance( ManagedRepositoryConfiguration repository, public RepositoryScannerInstance( ManagedRepositoryConfiguration repository,
List<KnownRepositoryContentConsumer> knownConsumerList, List<KnownRepositoryContentConsumer> knownConsumerList,
@ -120,14 +123,15 @@ public class RepositoryScannerInstance
stats.increaseFileCount(); stats.increaseFileCount();
// consume files regardless - the predicate will check the timestamp
BaseFile basefile = new BaseFile( repository.getLocation(), file );
// Timestamp finished points to the last successful scan, not this current one. // Timestamp finished points to the last successful scan, not this current one.
if ( file.lastModified() >= changesSince ) if ( file.lastModified() >= changesSince )
{ {
stats.increaseNewFileCount(); stats.increaseNewFileCount();
newFiles.add( basefile );
} }
// consume files regardless - the predicate will check the timestamp
BaseFile basefile = new BaseFile( repository.getLocation(), file );
consumerProcessFile.setBasefile( basefile ); consumerProcessFile.setBasefile( basefile );
consumerWantsFile.setBasefile( basefile ); consumerWantsFile.setBasefile( basefile );
@ -155,4 +159,9 @@ public class RepositoryScannerInstance
{ {
log.debug( "Repository Scanner: " + message ); log.debug( "Repository Scanner: " + message );
} }
public List<File> getNewFiles()
{
return newFiles;
}
} }

View File

@ -44,7 +44,8 @@ import com.sun.syndication.io.XmlReader;
/** /**
* Generates RSS feeds. * Generates RSS feeds.
* *
* @plexus.component role="org.apache.archiva.rss.RssFeedGenerator" * @plexus.component role="org.apache.archiva.rss.RssFeedGenerator"
* instantiation-strategy="per-lookup"
* *
* @author <a href="mailto:oching@apache.org">Maria Odea Ching</a> * @author <a href="mailto:oching@apache.org">Maria Odea Ching</a>
* @version * @version
@ -57,21 +58,21 @@ public class RssFeedGenerator
public static String DEFAULT_FEEDTYPE = "rss_2.0"; public static String DEFAULT_FEEDTYPE = "rss_2.0";
public static String DEFAULT_LANGUAGE = "en-us"; public static String DEFAULT_LANGUAGE = "en-us";
/** /**
* @plexus.configuration default-value="${appserver.base}/data/rss" * @plexus.configuration default-value="./apps/archiva/rss/"
*/ */
private String rssDirectory; private String rssDirectory;
public void generateFeed( String title, String link, String description, List<RssFeedEntry> dataEntries, public void generateFeed( String title, String link, String description, List<RssFeedEntry> dataEntries,
String outputFilename ) String outputFilename )
{ {
File outputFile = new File( rssDirectory, outputFilename ); File outputFile = new File( rssDirectory, outputFilename );
SyndFeed feed = null; SyndFeed feed = null;
List<SyndEntry> existingEntries = null; List<SyndEntry> existingEntries = null;
if( outputFile.exists() ) if ( outputFile.exists() )
{ {
try try
{ {
SyndFeedInput input = new SyndFeedInput(); SyndFeedInput input = new SyndFeedInput();
@ -88,25 +89,27 @@ public class RssFeedGenerator
} }
} }
else else
{ {
feed = new SyndFeedImpl(); feed = new SyndFeedImpl();
feed.setTitle( title ); feed.setTitle( title );
feed.setLink( link ); feed.setLink( link );
feed.setDescription( description ); feed.setDescription( description );
feed.setLanguage( DEFAULT_LANGUAGE ); feed.setLanguage( DEFAULT_LANGUAGE );
feed.setPublishedDate( Calendar.getInstance().getTime() );
} }
feed.setFeedType( DEFAULT_FEEDTYPE ); feed.setFeedType( DEFAULT_FEEDTYPE );
feed.setPublishedDate( Calendar.getInstance().getTime() );
feed.setEntries( getEntries( dataEntries, existingEntries ) ); feed.setEntries( getEntries( dataEntries, existingEntries ) );
try try
{ {
Writer writer = new FileWriter( outputFile ); Writer writer = new FileWriter( outputFile );
SyndFeedOutput output = new SyndFeedOutput(); SyndFeedOutput output = new SyndFeedOutput();
output.output( feed, writer ); output.output( feed, writer );
writer.close(); writer.close();
log.debug( "Finished writing feed to " + outputFile.getAbsolutePath() );
} }
catch ( IOException ie ) catch ( IOException ie )
{ {
@ -119,13 +122,13 @@ public class RssFeedGenerator
} }
private List<SyndEntry> getEntries( List<RssFeedEntry> dataEntries, List<SyndEntry> existingEntries ) private List<SyndEntry> getEntries( List<RssFeedEntry> dataEntries, List<SyndEntry> existingEntries )
{ {
List<SyndEntry> entries = existingEntries; List<SyndEntry> entries = existingEntries;
if( entries == null ) if ( entries == null )
{ {
entries = new ArrayList<SyndEntry>(); entries = new ArrayList<SyndEntry>();
} }
SyndEntry entry; SyndEntry entry;
SyndContent description; SyndContent description;
@ -151,4 +154,5 @@ public class RssFeedGenerator
{ {
this.rssDirectory = rssDirectory; this.rssDirectory = rssDirectory;
} }
} }

View File

@ -30,6 +30,8 @@ import org.apache.archiva.rss.RssFeedEntry;
import org.apache.archiva.rss.RssFeedGenerator; import org.apache.archiva.rss.RssFeedGenerator;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.maven.archiva.model.ArchivaArtifact; import org.apache.maven.archiva.model.ArchivaArtifact;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Process new artifacts in the repository and generate RSS feeds. * Process new artifacts in the repository and generate RSS feeds.
@ -50,12 +52,16 @@ public class NewArtifactsRssFeedProcessor
*/ */
private RssFeedGenerator generator; private RssFeedGenerator generator;
private Logger log = LoggerFactory.getLogger( NewArtifactsRssFeedProcessor.class );
/** /**
* Process the newly discovered artifacts in the repository. Generate feeds for new artifacts in the repository and * Process the newly discovered artifacts in the repository. Generate feeds for new artifacts in the repository and
* new versions of artifact. * new versions of artifact.
*/ */
public void process( List<ArchivaArtifact> data ) public void process( List<ArchivaArtifact> data )
{ {
log.debug( "Process new artifacts into rss feeds." );
processNewArtifactsInRepo( data ); processNewArtifactsInRepo( data );
processNewVersionsOfArtifact( data ); processNewVersionsOfArtifact( data );
} }
@ -67,19 +73,19 @@ public class NewArtifactsRssFeedProcessor
RssFeedEntry entry = RssFeedEntry entry =
new RssFeedEntry( NEW_ARTIFACTS_IN_REPO + "\'" + repoId + "\'" + " as of " + new RssFeedEntry( NEW_ARTIFACTS_IN_REPO + "\'" + repoId + "\'" + " as of " +
Calendar.getInstance().getTime(), "http://localhost:8080/archiva/repository/" + repoId ); Calendar.getInstance().getTime(), "http://localhost:8080/archiva/rss/new_artifacts_" + repoId + ".xml" );
String description = "These are the new artifacts found in repository " + "\'" + repoId + "\'" + ": \n"; String description = "These are the new artifacts found in repository " + "\'" + repoId + "\'" + ": \n";
for ( ArchivaArtifact artifact : data ) for ( ArchivaArtifact artifact : data )
{ {
description = description + artifact.toString() + "\n"; description = description + artifact.toString() + " | ";
} }
entry.setDescription( description ); entry.setDescription( description );
entries.add( entry ); entries.add( entry );
generateFeed( "new_artifacts_" + repoId + ".xml", NEW_ARTIFACTS_IN_REPO + "\'" + repoId + "\'", generateFeed( "new_artifacts_" + repoId + ".xml", NEW_ARTIFACTS_IN_REPO + "\'" + repoId + "\'",
"http://localhost:8080/archiva/repository/" + repoId, "New artifacts found in repository " + "http://localhost:8080/archiva/repository/rss/new_artifacts_" + repoId + ".xml",
"\'" + repoId + "\'" + " during repository scan.", entries ); "New artifacts found in repository " + "\'" + repoId + "\'" + " during repository scan.", entries );
} }
private void processNewVersionsOfArtifact( List<ArchivaArtifact> data ) private void processNewVersionsOfArtifact( List<ArchivaArtifact> data )
@ -100,21 +106,19 @@ public class NewArtifactsRssFeedProcessor
for ( String key : artifactsMap.keySet() ) for ( String key : artifactsMap.keySet() )
{ {
List<RssFeedEntry> entries = new ArrayList<RssFeedEntry>(); List<RssFeedEntry> entries = new ArrayList<RssFeedEntry>();
String artifactPath = getArtifactPath( key );
RssFeedEntry entry = RssFeedEntry entry =
new RssFeedEntry( NEW_VERSIONS_OF_ARTIFACT + "\'" + key + "\'" + " as of " + new RssFeedEntry( NEW_VERSIONS_OF_ARTIFACT + "\'" + key + "\'" + " as of " +
Calendar.getInstance().getTime(), "http://localhost:8080/archiva/repository/" + repoId + "/" + Calendar.getInstance().getTime(), "http://localhost:8080/archiva/rss/new_versions_" + key + ".xml" );
artifactPath );
String description = String description =
"These are the new versions of artifact " + "\'" + key + "\'" + " in the repository: \n" + "These are the new versions of artifact " + "\'" + key + "\'" + " in the repository: \n" +
StringUtils.replace( ( (String) artifactsMap.get( key ) ), "|", "\n" ); ( (String) artifactsMap.get( key ) );
entry.setDescription( description ); entry.setDescription( description );
entries.add( entry ); entries.add( entry );
generateFeed( "new_versions_" + repoId + "_" + key + ".xml", NEW_VERSIONS_OF_ARTIFACT + "\'" + key + "\'", generateFeed( "new_versions_" + key + ".xml", NEW_VERSIONS_OF_ARTIFACT + "\'" + key + "\'",
"http://localhost:8080/archiva/repository/" + repoId + "/" + artifactPath, "http://localhost:8080/archiva/rss/new_versions_" + key + ".xml",
"New versions of artifact " + "\'" + key + "\' found in repository " + "\'" + repoId + "\'" + "New versions of artifact " + "\'" + key + "\' found in repository " + "\'" + repoId + "\'" +
" during repository scan.", entries ); " during repository scan.", entries );
} }
@ -148,7 +152,7 @@ public class NewArtifactsRssFeedProcessor
String value = (String) artifactsMap.get( key ); String value = (String) artifactsMap.get( key );
if ( value != null ) if ( value != null )
{ {
value = value + "|" + id; value = value + " | " + id;
} }
else else
{ {
@ -160,16 +164,11 @@ public class NewArtifactsRssFeedProcessor
return artifactsMap; return artifactsMap;
} }
private String getArtifactPath( String key )
{
return StringUtils.replace( StringUtils.replace( key, ".", "/" ), ":", "/" );
}
public RssFeedGenerator getGenerator() public RssFeedGenerator getGenerator()
{ {
return generator; return generator;
} }
public void setGenerator( RssFeedGenerator generator ) public void setGenerator( RssFeedGenerator generator )
{ {
this.generator = generator; this.generator = generator;

View File

@ -93,16 +93,16 @@ public class NewArtifactsRssFeedProcessorTest
File outputFile = new File( rssDirectory, "new_artifacts_test-repo.xml" ); File outputFile = new File( rssDirectory, "new_artifacts_test-repo.xml" );
assertTrue( outputFile.exists() ); assertTrue( outputFile.exists() );
outputFile = new File( rssDirectory, "new_versions_test-repo_org.apache.archiva:artifact-one.xml" ); outputFile = new File( rssDirectory, "new_versions_org.apache.archiva:artifact-one.xml" );
assertTrue( outputFile.exists() ); assertTrue( outputFile.exists() );
outputFile = new File( rssDirectory, "new_versions_test-repo_org.apache.archiva:artifact-two.xml" ); outputFile = new File( rssDirectory, "new_versions_org.apache.archiva:artifact-two.xml" );
assertTrue( outputFile.exists() ); assertTrue( outputFile.exists() );
outputFile = new File( rssDirectory, "new_versions_test-repo_org.apache.archiva:artifact-three.xml" ); outputFile = new File( rssDirectory, "new_versions_org.apache.archiva:artifact-three.xml" );
assertTrue( outputFile.exists() ); assertTrue( outputFile.exists() );
outputFile = new File( rssDirectory, "new_versions_test-repo_org.apache.archiva:artifact-four.xml" ); outputFile = new File( rssDirectory, "new_versions_org.apache.archiva:artifact-four.xml" );
assertTrue( outputFile.exists() ); assertTrue( outputFile.exists() );
} }
} }

View File

@ -87,6 +87,10 @@
Delete Delete
</ww:a> </ww:a>
</redback:ifAnyAuthorized> </redback:ifAnyAuthorized>
<c:url var="rssFeedIconUrl" value="/images/icons/rss-feed.png"/>
<a href="/archiva/rss/new_artifacts_${repository.id}.xml">
<img src="${rssFeedIconUrl}" />
</a>
</div> </div>
<div style="float: left"> <div style="float: left">

View File

@ -62,14 +62,20 @@
<div id="nameColumn"> <div id="nameColumn">
<h2>Artifacts</h2> <h2>Artifacts</h2>
<ul> <ul>
<c:url var="rssFeedIconUrl" value="/images/icons/rss-feed.png"/>
<c:forEach items="${results.artifacts}" var="artifactId"> <c:forEach items="${results.artifacts}" var="artifactId">
<c:set var="url"> <c:set var="url">
<ww:url action="browseArtifact" namespace="/"> <ww:url action="browseArtifact" namespace="/">
<ww:param name="groupId" value="%{'${results.selectedGroupId}'}"/> <ww:param name="groupId" value="%{'${results.selectedGroupId}'}"/>
<ww:param name="artifactId" value="%{'${artifactId}'}"/> <ww:param name="artifactId" value="%{'${artifactId}'}"/>
</ww:url> </ww:url>
</c:set> </c:set>
<li><a href="${url}">${artifactId}/</a></li> <li>
<a href="${url}">${artifactId}/</a>
<a href="/archiva/rss/new_versions_${groupId}:${artifactId}.xml">
<img src="${rssFeedIconUrl}" />
</a>
</li>
</c:forEach> </c:forEach>
</ul> </ul>
</div> </div>

View File

@ -341,6 +341,11 @@
<artifactId>archiva-webdav</artifactId> <artifactId>archiva-webdav</artifactId>
<version>1.1-SNAPSHOT</version> <version>1.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-rss</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>org.codehaus.plexus</groupId> <groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-spring</artifactId> <artifactId>plexus-spring</artifactId>