[MERCURY-84] - fixed GA level snapshot metadata writer

git-svn-id: https://svn.apache.org/repos/asf/maven/mercury/trunk@740889 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/mercury-it/src/test/java/org/apache/maven/mercury/repository/tests/ComprehensiveRepositoryTest.java b/mercury-it/src/test/java/org/apache/maven/mercury/repository/tests/ComprehensiveRepositoryTest.java
index bc69d7f..7d66277 100644
--- a/mercury-it/src/test/java/org/apache/maven/mercury/repository/tests/ComprehensiveRepositoryTest.java
+++ b/mercury-it/src/test/java/org/apache/maven/mercury/repository/tests/ComprehensiveRepositoryTest.java
@@ -29,8 +29,11 @@
 import org.apache.maven.mercury.artifact.ArtifactBasicMetadata;
 import org.apache.maven.mercury.artifact.DefaultArtifact;
 import org.apache.maven.mercury.builder.api.DependencyProcessor;
+import org.apache.maven.mercury.repository.api.ArtifactResults;
+import org.apache.maven.mercury.repository.api.Repository;
 import org.apache.maven.mercury.repository.local.m2.LocalRepositoryM2;
 import org.apache.maven.mercury.repository.remote.m2.RemoteRepositoryM2;
+import org.apache.maven.mercury.repository.virtual.VirtualRepositoryReader;
 import org.apache.maven.mercury.transport.api.Credentials;
 import org.apache.maven.mercury.transport.api.Server;
 import org.apache.maven.mercury.util.FileUtil;
@@ -69,6 +72,10 @@
     
     static final String _resourceBase = "./target/test-classes";
     
+    List<Repository> _rrs;
+    List<Repository> _lrs;
+    List<Repository> _repos;
+    
     
     @Override
     protected void setUp()
@@ -99,6 +106,10 @@
         server = new Server("rr2", new URL("http://localhost:"+_port2+_context2), false, false, user );
         _rr2 = new RemoteRepositoryM2( server, dp );
         
+        _rrs = new ArrayList<Repository>(2);
+        _rrs.add( _rr1 );
+        _rrs.add( _rr2 );
+        
         _lbase1 = new File( _local1 );
         FileUtil.delete( _lbase1 );
         _lbase1.mkdirs();
@@ -109,6 +120,13 @@
         _lbase2.mkdirs();
         _lr2 = new LocalRepositoryM2( "lr2", _lbase2, dp );
         
+        _lrs = new ArrayList<Repository>(2);
+        _lrs.add( _lr1 );
+        _lrs.add( _lr2 );
+        
+        _repos = new ArrayList<Repository>();
+        _repos.addAll( _rrs );
+        _repos.addAll( _lrs );
     }
 
     @Override
@@ -136,19 +154,141 @@
             finally { _server2 = null; }
     }
     
-    public void testWriteReadArtifact()
+    public void writeArtifact( String name, File af, File ap, Repository repo )
     throws Exception
     {
-        File af = new File( _resourceBase, "maven-core-2.0.9.jar" );
-        File ap = new File( _resourceBase, "maven-core-2.0.9.pom" );
-        
-        DefaultArtifact da = new DefaultArtifact( new ArtifactBasicMetadata("org.apache.maven:maven-core:2.0.9") );
+        DefaultArtifact da = new DefaultArtifact( new ArtifactBasicMetadata(name) );
         
         da.setPomBlob( FileUtil.readRawData( ap ) );
         da.setFile( af );
         List<Artifact> al = new ArrayList<Artifact>();
         al.add( da );
         
-        _rr2.getWriter().writeArtifacts( al );
+        repo.getWriter().writeArtifacts( al );
+    }
+    
+    public List<Artifact> readArtifact( String name , List<Repository> repos )
+    throws Exception
+    {
+        ArtifactBasicMetadata bmd = new ArtifactBasicMetadata(name);
+        
+        List<ArtifactBasicMetadata> al = new ArrayList<ArtifactBasicMetadata>();
+        al.add( bmd );
+        
+        VirtualRepositoryReader vr = new VirtualRepositoryReader( repos );
+        
+        ArtifactResults  res = vr.readArtifacts( al );
+        
+        assertNotNull( res );
+        
+        if( res.hasExceptions() )
+            System.out.println( res.getExceptions() );
+        
+        assertTrue( res.hasResults(bmd) );
+        
+        return res.getResults( bmd );
+    }
+    
+    public void testWriteReadArtifact()
+    throws Exception
+    {
+        String name = "org.apache.maven:maven-core:2.0.9";
+        ArtifactBasicMetadata bmd = new ArtifactBasicMetadata( name );
+        
+        File af = new File( _resourceBase, "maven-core-2.0.9.jar" );
+        File ap = new File( _resourceBase, "maven-core-2.0.9.pom" );
+        
+        File aJar1 = new File( _base1, "org/apache/maven/maven-core/2.0.9/maven-core-2.0.9.jar");
+        File aJar2 = new File( _base2, "org/apache/maven/maven-core/2.0.9/maven-core-2.0.9.jar");
+        
+        assertFalse( aJar1.exists() );
+        assertFalse( aJar2.exists() );
+        
+        writeArtifact( name, af, ap, _rr2 );
+        
+        assertFalse( aJar1.exists() );
+        assertTrue( aJar2.exists() );
+        
+        List<Artifact> al = readArtifact( name, _rrs );
+        
+        System.out.println(al);
+        
+        File localRepo1Jar = new File( _lbase1, "org/apache/maven/maven-core/2.0.9/maven-core-2.0.9.jar" );
+        File localRepo2Jar = new File( _lbase2, "org/apache/maven/maven-core/2.0.9/maven-core-2.0.9.jar" );
+        
+        assertFalse( localRepo1Jar.exists() );
+        assertFalse( localRepo2Jar.exists() );
+        
+        al = readArtifact( name, _repos );
+        
+        assertTrue( localRepo1Jar.exists() );
+        assertFalse( localRepo2Jar.exists() );
+    }
+    
+    public void testWriteReadTimeStamp()
+    throws Exception
+    {
+        String name = "org.apache.maven:maven-core:2.0.9-20090204.232323-23";
+        ArtifactBasicMetadata bmd = new ArtifactBasicMetadata( name );
+        
+        File af = new File( _resourceBase, "maven-core-2.0.9.jar" );
+        File ap = new File( _resourceBase, "maven-core-2.0.9.pom" );
+        
+        File aJar1 = new File( _base1, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar");
+        File aJar2 = new File( _base2, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar");
+        
+        assertFalse( aJar1.exists() );
+        assertFalse( aJar2.exists() );
+        
+        writeArtifact( name, af, ap, _rr2 );
+        
+        assertFalse( aJar1.exists() );
+        assertTrue( aJar2.exists() );
+        
+        List<Artifact> al = readArtifact( name, _rrs );
+        
+        System.out.println(al);
+        
+        File localRepo1Jar = new File( _lbase1, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar" );
+        File localRepo2Jar = new File( _lbase2, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar" );
+        
+        assertFalse( localRepo1Jar.exists() );
+        assertFalse( localRepo2Jar.exists() );
+        
+        al = readArtifact( name, _repos );
+        
+        assertTrue( localRepo1Jar.exists() );
+        assertFalse( localRepo2Jar.exists() );
+    }
+    
+    public void testWriteReadLocalTimeStamp()
+    throws Exception
+    {
+        String name = "org.apache.maven:maven-core:2.0.9-20090204.232323-23";
+        ArtifactBasicMetadata bmd = new ArtifactBasicMetadata( name );
+        
+        File af = new File( _resourceBase, "maven-core-2.0.9.jar" );
+        File ap = new File( _resourceBase, "maven-core-2.0.9.pom" );
+        
+        File aJar1 = new File( _lbase1, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar");
+        File aJar2 = new File( _lbase2, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar");
+        
+        assertFalse( aJar1.exists() );
+        assertFalse( aJar2.exists() );
+        
+        writeArtifact( name, af, ap, _lr2 );
+        
+        assertFalse( aJar1.exists() );
+        assertTrue( aJar2.exists() );
+        
+        List<Artifact> al = readArtifact( name, _repos );
+        
+        System.out.println(al);
+        
+        File localRepo1Jar = new File( _lbase1, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar" );
+        File localRepo2Jar = new File( _lbase2, "org/apache/maven/maven-core/2.0.9-SNAPSHOT/maven-core-2.0.9-20090204.232323-23.jar" );
+        
+        assertTrue( localRepo1Jar.exists() );
+        assertTrue( localRepo2Jar.exists() );
     }
 }
diff --git a/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/Messages.properties b/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/Messages.properties
index c056dac..fb73bcd 100644
--- a/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/Messages.properties
+++ b/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/Messages.properties
@@ -19,4 +19,6 @@
 bad.operand=Operand is not correct: expected {0}, but got {1}
 empty.operand=Operand cannot be null or empty: {0}
 bad.string.data=cannot initialize from an empty string: {0}
-bad.snapshot.data=null snapshot passed as parameter
\ No newline at end of file
+bad.snapshot.data=null snapshot passed as parameter
+
+bad.snapshot.version=the supplied version {0} cannot be parsed as a timestamped snapshot, expected: xxx-timeStamp-buildNo
\ No newline at end of file
diff --git a/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/MetadataBuilder.java b/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/MetadataBuilder.java
index 43f83c0..ea90ba8 100644
--- a/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/MetadataBuilder.java
+++ b/mercury-md/mercury-md-shared/src/main/java/org/apache/maven/mercury/repository/metadata/MetadataBuilder.java
@@ -22,7 +22,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -30,6 +29,8 @@
 import org.apache.maven.mercury.repository.metadata.io.xpp3.MetadataXpp3Reader;
 import org.apache.maven.mercury.repository.metadata.io.xpp3.MetadataXpp3Writer;
 import org.apache.maven.mercury.util.TimeUtil;
+import org.codehaus.plexus.lang.DefaultLanguage;
+import org.codehaus.plexus.lang.Language;
 import org.codehaus.plexus.util.WriterFactory;
 
 /**
@@ -40,7 +41,7 @@
  */
 public class MetadataBuilder
 {
-
+    private static final Language LANG = new DefaultLanguage( MetadataBuilder.class );
     /**
      * instantiate Metadata from a stream
      * 
@@ -263,9 +264,23 @@
             return sn;
         }
 
-        String sbn = version.substring( version.lastIndexOf( '-' ) + 1 );
+        int pos = version.lastIndexOf( '-' );
+        
+        if( pos == -1 )
+            throw new IllegalArgumentException( LANG.getMessage( "bad.snapshot.version", version ) );
+
+        String sbn = version.substring( pos + 1 );
+        
         int bn = Integer.parseInt( sbn );
         sn.setBuildNumber( bn );
+        
+        String sts = version.substring( 0, pos);
+        pos = sts.lastIndexOf( '-' );
+        
+        if( pos == -1 )
+            throw new IllegalArgumentException( LANG.getMessage( "bad.snapshot.version", version ) );
+        
+        sn.setTimestamp( sts.substring( pos+1 ) );
 
         return sn;
     }
diff --git a/mercury-repo/mercury-repo-remote-m2/src/main/java/org/apache/maven/mercury/repository/remote/m2/RemoteRepositoryWriterM2.java b/mercury-repo/mercury-repo-remote-m2/src/main/java/org/apache/maven/mercury/repository/remote/m2/RemoteRepositoryWriterM2.java
index 3c5612c..d94ce38 100644
--- a/mercury-repo/mercury-repo-remote-m2/src/main/java/org/apache/maven/mercury/repository/remote/m2/RemoteRepositoryWriterM2.java
+++ b/mercury-repo/mercury-repo-remote-m2/src/main/java/org/apache/maven/mercury/repository/remote/m2/RemoteRepositoryWriterM2.java
@@ -24,8 +24,10 @@
 import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.maven.mercury.artifact.Artifact;
@@ -66,8 +68,8 @@
 extends AbstractRepositoryWriter
 implements RepositoryWriter
 {
-  private static final IMercuryLogger _log = MercuryLoggerManager.getLogger( RemoteRepositoryWriterM2.class ); 
-  private static final Language _lang = new DefaultLanguage( RemoteRepositoryWriterM2.class );
+  private static final IMercuryLogger LOG = MercuryLoggerManager.getLogger( RemoteRepositoryWriterM2.class ); 
+  private static final Language LANG = new DefaultLanguage( RemoteRepositoryWriterM2.class );
   //---------------------------------------------------------------------------------------------------------------
   private static final String [] _protocols = new String [] { "http", "https", "dav", "webdav" };
   
@@ -86,10 +88,10 @@
     
     _server = repo.getServer();
     if( _server == null )
-      throw new IllegalArgumentException( _lang.getMessage( "bad.repository.server.null" ) );
+      throw new IllegalArgumentException( LANG.getMessage( "bad.repository.server.null" ) );
     
     if( _server.getURL() == null )
-      throw new IllegalArgumentException(_lang.getMessage( "bad.repository.server.url.null" ));
+      throw new IllegalArgumentException(LANG.getMessage( "bad.repository.server.url.null" ));
 
     _repo = repo;
     
@@ -151,10 +153,10 @@
   throws RepositoryException
   {
     if( artifact == null )
-      throw new RepositoryException( _lang.getMessage( "null.artifact") );
+      throw new RepositoryException( LANG.getMessage( "null.artifact") );
     
     if( artifact.getFile() == null || !artifact.getFile().exists() )
-      throw new RepositoryException( _lang.getMessage( "bad.artifact.file", artifact.toString(), (artifact.getFile() == null ? "null" : artifact.getFile().getAbsolutePath()) ) );
+      throw new RepositoryException( LANG.getMessage( "bad.artifact.file", artifact.toString(), (artifact.getFile() == null ? "null" : artifact.getFile().getAbsolutePath()) ) );
     
     boolean isPom = "pom".equals( artifact.getType() );
     
@@ -162,7 +164,7 @@
     boolean hasPomBlob = pomBlob != null && pomBlob.length > 0;
     
     if( !artifact.hasClassifier() && !hasPomBlob )
-      throw new RepositoryException( _lang.getMessage( "no.pom.in.primary.artifact", artifact.toString() ) );
+      throw new RepositoryException( LANG.getMessage( "no.pom.in.primary.artifact", artifact.toString() ) );
     
     InputStream in = artifact.getStream();
     if( in == null )
@@ -170,7 +172,7 @@
       File aFile = artifact.getFile();
       if( aFile == null && !isPom )
       {
-        throw new RepositoryException( _lang.getMessage( "artifact.no.stream", artifact.toString() ) );
+        throw new RepositoryException( LANG.getMessage( "artifact.no.stream", artifact.toString() ) );
       }
 
       try
@@ -180,7 +182,7 @@
       catch( FileNotFoundException e )
       {
         if( !isPom )
-          throw new RepositoryException( _lang.getMessage( "artifact.no.file", artifact.toString(), aFile.getAbsolutePath(), e.getMessage() ) );
+          throw new RepositoryException( LANG.getMessage( "artifact.no.file", artifact.toString(), aFile.getAbsolutePath(), e.getMessage() ) );
       }
     }
     DefaultArtifactVersion dav = new DefaultArtifactVersion( artifact.getVersion() );
@@ -188,14 +190,15 @@
     boolean isSnapshot = aq.equals( Quality.SNAPSHOT_QUALITY ) || aq.equals( Quality.SNAPSHOT_TS_QUALITY );
 
     String relGroupPath = artifact.getGroupId().replace( '.', '/' )+"/"+artifact.getArtifactId();
-    String relVersionPath = relGroupPath + '/' + (isSnapshot ? (dav.getBase()+'-'+Artifact.SNAPSHOT_VERSION) : artifact.getVersion() );
+    String versionFolder = (isSnapshot ? (dav.getBase()+'-'+Artifact.SNAPSHOT_VERSION) : artifact.getVersion() );
+    String relVersionPath = relGroupPath + '/' + versionFolder;
 
     try
     {
       if( isPom )
       {
         if( in == null && !hasPomBlob )
-          throw new RepositoryException( _lang.getMessage( "pom.artifact.no.stream", artifact.toString() ) );
+          throw new RepositoryException( LANG.getMessage( "pom.artifact.no.stream", artifact.toString() ) );
         
         if( in != null )
         {
@@ -232,18 +235,19 @@
         md.setArtifactId( artifact.getArtifactId() );
       }
       
-      MetadataOperation mdOp = null;
+      List<MetadataOperation> ops = new ArrayList<MetadataOperation>(2); 
       
       if( isSnapshot )
       {
         Snapshot sn = MetadataBuilder.createSnapshot( artifact.getVersion() );
         sn.setLocalCopy( true );
-        mdOp = new SetSnapshotOperation( new SnapshotOperand(sn) );
+        ops.add( new SetSnapshotOperation( new SnapshotOperand(sn) ) );
+        ops.add( new AddVersionOperation( new StringOperand(versionFolder) ) );
       }
       else
-        mdOp = new AddVersionOperation( new StringOperand(artifact.getVersion()) ); 
+          ops.add( new AddVersionOperation( new StringOperand(artifact.getVersion()) ) ); 
       
-      byte [] gaResBytes = MetadataBuilder.changeMetadata( md, mdOp );
+      byte [] gaResBytes = MetadataBuilder.changeMetadata( md, ops );
       Metadata gaMd = MetadataBuilder.getMetadata( gaResBytes );
       
       bindings.add( new Binding(new URL(gaMdUrl), new ByteArrayInputStream(gaResBytes)) );
@@ -259,6 +263,7 @@
         md.setVersion( artifact.getVersion() );
       }
       
+      MetadataOperation mdOp = new AddVersionOperation( new StringOperand(artifact.getVersion()) );
       byte [] gavResBytes = MetadataBuilder.changeMetadata( md, mdOp );
       Metadata gavMd = MetadataBuilder.getMetadata( gavResBytes );