Coverage Report - org.apache.maven.archiva.repository.metadata.MetadataTools
 
Classes in this File Line Coverage Branch Coverage Complexity
MetadataTools
0%
0/309
0%
0/128
0
 
 1  
 package org.apache.maven.archiva.repository.metadata;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.archiva.checksum.ChecksumAlgorithm;
 23  
 import org.apache.archiva.checksum.ChecksummedFile;
 24  
 import org.apache.commons.collections.CollectionUtils;
 25  
 import org.apache.commons.lang.StringUtils;
 26  
 import org.apache.commons.lang.math.NumberUtils;
 27  
 import org.apache.commons.lang.time.DateUtils;
 28  
 import org.apache.maven.archiva.common.utils.PathUtil;
 29  
 import org.apache.maven.archiva.common.utils.VersionComparator;
 30  
 import org.apache.maven.archiva.common.utils.VersionUtil;
 31  
 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
 32  
 import org.apache.maven.archiva.configuration.ConfigurationNames;
 33  
 import org.apache.maven.archiva.configuration.FileTypes;
 34  
 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
 35  
 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
 36  
 import org.apache.maven.archiva.model.ArtifactReference;
 37  
 import org.apache.maven.archiva.model.Plugin;
 38  
 import org.apache.maven.archiva.model.ProjectReference;
 39  
 import org.apache.maven.archiva.model.SnapshotVersion;
 40  
 import org.apache.maven.archiva.model.VersionedReference;
 41  
 import org.apache.maven.archiva.repository.ContentNotFoundException;
 42  
 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
 43  
 import org.apache.maven.archiva.repository.RemoteRepositoryContent;
 44  
 import org.apache.maven.archiva.repository.layout.LayoutException;
 45  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
 46  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
 47  
 import org.codehaus.plexus.registry.Registry;
 48  
 import org.codehaus.plexus.registry.RegistryListener;
 49  
 import org.slf4j.Logger;
 50  
 import org.slf4j.LoggerFactory;
 51  
 
 52  
 import java.io.File;
 53  
 import java.io.IOException;
 54  
 import java.text.ParseException;
 55  
 import java.text.SimpleDateFormat;
 56  
 import java.util.ArrayList;
 57  
 import java.util.Calendar;
 58  
 import java.util.Collection;
 59  
 import java.util.Collections;
 60  
 import java.util.Date;
 61  
 import java.util.HashMap;
 62  
 import java.util.HashSet;
 63  
 import java.util.Iterator;
 64  
 import java.util.LinkedHashSet;
 65  
 import java.util.List;
 66  
 import java.util.Map;
 67  
 import java.util.Set;
 68  
 import java.util.regex.Matcher;
 69  
 import org.apache.commons.io.FileUtils;
 70  
 
 71  
 /**
 72  
  * MetadataTools
 73  
  *
 74  
  * @version $Id: MetadataTools.java 718864 2008-11-19 06:33:35Z brett $
 75  
  * 
 76  
  * @plexus.component role="org.apache.maven.archiva.repository.metadata.MetadataTools"
 77  
  */
 78  
 public class MetadataTools
 79  
     implements RegistryListener, Initializable
 80  
 {
 81  0
     private static Logger log = LoggerFactory.getLogger( MetadataTools.class );
 82  
 
 83  
     public static final String MAVEN_METADATA = "maven-metadata.xml";
 84  
 
 85  
     private static final char PATH_SEPARATOR = '/';
 86  
 
 87  
     private static final char GROUP_SEPARATOR = '.';
 88  
 
 89  
     /**
 90  
      * @plexus.requirement
 91  
      */
 92  
     private ArchivaConfiguration configuration;
 93  
 
 94  
     /**
 95  
      * @plexus.requirement
 96  
      */
 97  
     private FileTypes filetypes;
 98  
     
 99  0
     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
 100  
     
 101  
     private List<String> artifactPatterns;
 102  
 
 103  
     private Map<String, Set<String>> proxies;
 104  
 
 105  0
     private static final char NUMS[] = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
 106  
 
 107  
     private SimpleDateFormat lastUpdatedFormat;
 108  
 
 109  
     public MetadataTools()
 110  0
     {
 111  0
         lastUpdatedFormat = new SimpleDateFormat( "yyyyMMddHHmmss" );
 112  0
         lastUpdatedFormat.setTimeZone( DateUtils.UTC_TIME_ZONE );
 113  0
     }
 114  
 
 115  
     public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
 116  
     {
 117  0
         if ( ConfigurationNames.isProxyConnector( propertyName ) )
 118  
         {
 119  0
             initConfigVariables();
 120  
         }
 121  0
     }
 122  
 
 123  
     public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
 124  
     {
 125  
         /* nothing to do */
 126  0
     }
 127  
 
 128  
     /**
 129  
      * Gather the set of snapshot versions found in a particular versioned reference.
 130  
      *
 131  
      * @return the Set of snapshot artifact versions found.
 132  
      * @throws LayoutException
 133  
      * @throws ContentNotFoundException 
 134  
      */
 135  
     public Set<String> gatherSnapshotVersions( ManagedRepositoryContent managedRepository, VersionedReference reference )
 136  
         throws LayoutException, IOException, ContentNotFoundException
 137  
     {
 138  0
         Set<String> foundVersions = managedRepository.getVersions( reference );
 139  
 
 140  
         // Next gather up the referenced 'latest' versions found in any proxied repositories
 141  
         // maven-metadata-${proxyId}.xml files that may be present.
 142  
 
 143  
         // Does this repository have a set of remote proxied repositories?
 144  0
         Set<String> proxiedRepoIds = this.proxies.get( managedRepository.getId() );
 145  
 
 146  0
         if ( CollectionUtils.isNotEmpty( proxiedRepoIds ) )
 147  
         {
 148  0
             String baseVersion = VersionUtil.getBaseVersion( reference.getVersion() );
 149  0
             baseVersion = baseVersion.substring( 0, baseVersion.indexOf( VersionUtil.SNAPSHOT ) - 1 );
 150  
 
 151  
             // Add in the proxied repo version ids too.
 152  0
             Iterator<String> it = proxiedRepoIds.iterator();
 153  0
             while ( it.hasNext() )
 154  
             {
 155  0
                 String proxyId = it.next();
 156  
 
 157  0
                 ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, reference, proxyId );
 158  0
                 if ( proxyMetadata == null )
 159  
                 {
 160  
                     // There is no proxy metadata, skip it.
 161  0
                     continue;
 162  
                 }
 163  
 
 164  
                 // Is there some snapshot info?
 165  0
                 SnapshotVersion snapshot = proxyMetadata.getSnapshotVersion();
 166  0
                 if ( snapshot != null )
 167  
                 {
 168  0
                     String timestamp = snapshot.getTimestamp();
 169  0
                     int buildNumber = snapshot.getBuildNumber();
 170  
 
 171  
                     // Only interested in the timestamp + buildnumber.
 172  0
                     if ( StringUtils.isNotBlank( timestamp ) && ( buildNumber > 0 ) )
 173  
                     {
 174  0
                         foundVersions.add( baseVersion + "-" + timestamp + "-" + buildNumber );
 175  
                     }
 176  
                 }
 177  0
             }
 178  
         }
 179  
 
 180  0
         return foundVersions;
 181  
     }
 182  
 
 183  
     /**
 184  
      * Take a path to a maven-metadata.xml, and attempt to translate it to a VersionedReference.
 185  
      *
 186  
      * @param path
 187  
      * @return
 188  
      */
 189  
     public VersionedReference toVersionedReference( String path )
 190  
         throws RepositoryMetadataException
 191  
     {
 192  0
         if ( !path.endsWith( "/" + MAVEN_METADATA ) )
 193  
         {
 194  0
             throw new RepositoryMetadataException( "Cannot convert to versioned reference, not a metadata file. " );
 195  
         }
 196  
 
 197  0
         VersionedReference reference = new VersionedReference();
 198  
 
 199  0
         String normalizedPath = StringUtils.replace( path, "\\", "/" );
 200  0
         String pathParts[] = StringUtils.split( normalizedPath, '/' );
 201  
 
 202  0
         int versionOffset = pathParts.length - 2;
 203  0
         int artifactIdOffset = versionOffset - 1;
 204  0
         int groupIdEnd = artifactIdOffset - 1;
 205  
 
 206  0
         reference.setVersion( pathParts[versionOffset] );
 207  
 
 208  0
         if ( !hasNumberAnywhere( reference.getVersion() ) )
 209  
         {
 210  
             // Scary check, but without it, all paths are version references;
 211  0
             throw new RepositoryMetadataException(
 212  
                                                    "Not a versioned reference, as version id on path has no number in it." );
 213  
         }
 214  
 
 215  0
         reference.setArtifactId( pathParts[artifactIdOffset] );
 216  
 
 217  0
         StringBuffer gid = new StringBuffer();
 218  0
         for ( int i = 0; i <= groupIdEnd; i++ )
 219  
         {
 220  0
             if ( i > 0 )
 221  
             {
 222  0
                 gid.append( "." );
 223  
             }
 224  0
             gid.append( pathParts[i] );
 225  
         }
 226  
 
 227  0
         reference.setGroupId( gid.toString() );
 228  
 
 229  0
         return reference;
 230  
     }
 231  
 
 232  
     private boolean hasNumberAnywhere( String version )
 233  
     {
 234  0
         return StringUtils.indexOfAny( version, NUMS ) != ( -1 );
 235  
     }
 236  
 
 237  
     public ProjectReference toProjectReference( String path )
 238  
         throws RepositoryMetadataException
 239  
     {
 240  0
         if ( !path.endsWith( "/" + MAVEN_METADATA ) )
 241  
         {
 242  0
             throw new RepositoryMetadataException( "Cannot convert to versioned reference, not a metadata file. " );
 243  
         }
 244  
 
 245  0
         ProjectReference reference = new ProjectReference();
 246  
 
 247  0
         String normalizedPath = StringUtils.replace( path, "\\", "/" );
 248  0
         String pathParts[] = StringUtils.split( normalizedPath, '/' );
 249  
 
 250  
         // Assume last part of the path is the version.
 251  
 
 252  0
         int artifactIdOffset = pathParts.length - 2;
 253  0
         int groupIdEnd = artifactIdOffset - 1;
 254  
 
 255  0
         reference.setArtifactId( pathParts[artifactIdOffset] );
 256  
 
 257  0
         StringBuffer gid = new StringBuffer();
 258  0
         for ( int i = 0; i <= groupIdEnd; i++ )
 259  
         {
 260  0
             if ( i > 0 )
 261  
             {
 262  0
                 gid.append( "." );
 263  
             }
 264  0
             gid.append( pathParts[i] );
 265  
         }
 266  
 
 267  0
         reference.setGroupId( gid.toString() );
 268  
 
 269  0
         return reference;
 270  
     }
 271  
 
 272  
     public String toPath( ProjectReference reference )
 273  
     {
 274  0
         StringBuffer path = new StringBuffer();
 275  
 
 276  0
         path.append( formatAsDirectory( reference.getGroupId() ) ).append( PATH_SEPARATOR );
 277  0
         path.append( reference.getArtifactId() ).append( PATH_SEPARATOR );
 278  0
         path.append( MAVEN_METADATA );
 279  
 
 280  0
         return path.toString();
 281  
     }
 282  
 
 283  
     public String toPath( VersionedReference reference )
 284  
     {
 285  0
         StringBuffer path = new StringBuffer();
 286  
 
 287  0
         path.append( formatAsDirectory( reference.getGroupId() ) ).append( PATH_SEPARATOR );
 288  0
         path.append( reference.getArtifactId() ).append( PATH_SEPARATOR );
 289  0
         if ( reference.getVersion() != null )
 290  
         {
 291  
             // add the version only if it is present
 292  0
             path.append( VersionUtil.getBaseVersion( reference.getVersion() ) ).append( PATH_SEPARATOR );
 293  
         }
 294  0
         path.append( MAVEN_METADATA );
 295  
 
 296  0
         return path.toString();
 297  
     }
 298  
 
 299  
     private String formatAsDirectory( String directory )
 300  
     {
 301  0
         return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );
 302  
     }
 303  
 
 304  
     /**
 305  
      * Adjusts a path for a metadata.xml file to its repository specific path.
 306  
      *
 307  
      * @param repository the repository to base new path off of.
 308  
      * @param path       the path to the metadata.xml file to adjust the name of.
 309  
      * @return the newly adjusted path reference to the repository specific metadata path.
 310  
      */
 311  
     public String getRepositorySpecificName( RemoteRepositoryContent repository, String path )
 312  
     {
 313  0
         return getRepositorySpecificName( repository.getId(), path );
 314  
     }
 315  
 
 316  
     /**
 317  
      * Adjusts a path for a metadata.xml file to its repository specific path.
 318  
      *
 319  
      * @param proxyId the repository id to base new path off of.
 320  
      * @param path    the path to the metadata.xml file to adjust the name of.
 321  
      * @return the newly adjusted path reference to the repository specific metadata path.
 322  
      */
 323  
     public String getRepositorySpecificName( String proxyId, String path )
 324  
     {
 325  0
         StringBuffer ret = new StringBuffer();
 326  
 
 327  0
         int idx = path.lastIndexOf( "/" );
 328  0
         if ( idx > 0 )
 329  
         {
 330  0
             ret.append( path.substring( 0, idx + 1 ) );
 331  
         }
 332  
 
 333  
         // TODO: need to filter out 'bad' characters from the proxy id.
 334  0
         ret.append( "maven-metadata-" ).append( proxyId ).append( ".xml" );
 335  
 
 336  0
         return ret.toString();
 337  
     }
 338  
 
 339  
     public void initialize()
 340  
         throws InitializationException
 341  
     {
 342  0
         this.artifactPatterns = new ArrayList<String>();
 343  0
         this.proxies = new HashMap<String, Set<String>>();
 344  0
         initConfigVariables();
 345  
 
 346  0
         configuration.addChangeListener( this );
 347  0
     }
 348  
 
 349  
     public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository,
 350  
                                                         ProjectReference reference, String proxyId )
 351  
     {
 352  0
         String metadataPath = getRepositorySpecificName( proxyId, toPath( reference ) );
 353  0
         File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath );
 354  
         
 355  0
         if ( !metadataFile.exists() || !metadataFile.isFile() )
 356  
         {
 357  
             // Nothing to do. return null.
 358  0
             return null;
 359  
         }
 360  
 
 361  
         try
 362  
         {
 363  0
             return RepositoryMetadataReader.read( metadataFile );
 364  
         }
 365  0
         catch ( RepositoryMetadataException e )
 366  
         {
 367  
             // TODO: [monitor] consider a monitor for this event.
 368  
             // TODO: consider a read-redo on monitor return code?
 369  0
             log.warn( "Unable to read metadata: " + metadataFile.getAbsolutePath(), e );
 370  0
             return null;
 371  
         }
 372  
     }
 373  
     
 374  
     public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository,
 375  
                                                         String logicalResource, String proxyId )
 376  
     {
 377  0
         String metadataPath = getRepositorySpecificName( proxyId, logicalResource );
 378  0
         File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath );
 379  
         
 380  0
         if ( !metadataFile.exists() || !metadataFile.isFile() )
 381  
         {
 382  
             // Nothing to do. return null.
 383  0
             return null;
 384  
         }
 385  
 
 386  
         try
 387  
         {
 388  0
             return RepositoryMetadataReader.read( metadataFile );
 389  
         }
 390  0
         catch ( RepositoryMetadataException e )
 391  
         {
 392  
             // TODO: [monitor] consider a monitor for this event.
 393  
             // TODO: consider a read-redo on monitor return code?
 394  0
             log.warn( "Unable to read metadata: " + metadataFile.getAbsolutePath(), e );
 395  0
             return null;
 396  
         }
 397  
     }
 398  
 
 399  
     public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository,
 400  
                                                         VersionedReference reference, String proxyId )
 401  
     {
 402  0
         String metadataPath = getRepositorySpecificName( proxyId, toPath( reference ) );
 403  0
         File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath );
 404  
         
 405  0
         if ( !metadataFile.exists() || !metadataFile.isFile() )
 406  
         {
 407  
             // Nothing to do. return null.
 408  0
             return null;
 409  
         }
 410  
 
 411  
         try
 412  
         {
 413  0
             return RepositoryMetadataReader.read( metadataFile );
 414  
         }
 415  0
         catch ( RepositoryMetadataException e )
 416  
         {
 417  
             // TODO: [monitor] consider a monitor for this event.
 418  
             // TODO: consider a read-redo on monitor return code?
 419  0
             log.warn( "Unable to read metadata: " + metadataFile.getAbsolutePath(), e );
 420  0
             return null;
 421  
         }
 422  
     }
 423  
     
 424  
     public void updateMetadata( ManagedRepositoryContent managedRepository, String logicalResource) throws RepositoryMetadataException
 425  
     {
 426  0
         final File metadataFile = new File(managedRepository.getRepoRoot(), logicalResource);
 427  0
         ArchivaRepositoryMetadata metadata = null;
 428  
         
 429  
         //Gather and merge all metadata available
 430  0
         List<ArchivaRepositoryMetadata> metadatas = getMetadatasForManagedRepository(managedRepository, logicalResource);
 431  0
         for (ArchivaRepositoryMetadata proxiedMetadata : metadatas)
 432  
         {
 433  0
             if (metadata == null)
 434  
             {
 435  0
                 metadata = proxiedMetadata;
 436  0
                 continue;
 437  
             }
 438  0
             metadata = RepositoryMetadataMerge.merge(metadata, proxiedMetadata);
 439  
         }
 440  
         
 441  0
         if (metadata == null)
 442  
         {
 443  0
             log.debug("No metadata to update for " + logicalResource);
 444  0
             return;
 445  
         }
 446  
         
 447  0
         Set<String> availableVersions = new HashSet<String>();
 448  0
         List<String> metadataAvailableVersions = metadata.getAvailableVersions();
 449  0
         if (metadataAvailableVersions != null)
 450  
         {
 451  0
             availableVersions.addAll(metadataAvailableVersions);
 452  
         }
 453  0
         availableVersions = findPossibleVersions(availableVersions, metadataFile.getParentFile());
 454  
 
 455  0
         if (availableVersions.size() > 0)
 456  
         {
 457  0
             updateMetadataVersions(availableVersions, metadata);
 458  
         }
 459  
         
 460  0
         RepositoryMetadataWriter.write(metadata, metadataFile);
 461  
         
 462  0
         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
 463  0
         checksum.fixChecksums( algorithms );
 464  0
     }
 465  
     
 466  
     /**
 467  
      * Skims the parent directory of a metadata in vain hope of finding 
 468  
      * subdirectories that contain poms.
 469  
      * 
 470  
      * @param metadataParentDirectory
 471  
      * @return origional set plus newley found versions
 472  
      */
 473  
     private Set<String> findPossibleVersions(Set<String> versions, File metadataParentDirectory)
 474  
     {
 475  0
         Set<String> result = new HashSet<String>(versions);
 476  0
         for (File directory : metadataParentDirectory.listFiles())
 477  
         {
 478  0
             if (directory.isDirectory())
 479  
             {
 480  0
                 for (File possiblePom : directory.listFiles())
 481  
                 {
 482  0
                     if (possiblePom.getName().endsWith(".pom"))
 483  
                     {
 484  0
                         result.add(directory.getName());
 485  
                     }
 486  
                 }
 487  
             }
 488  
         }
 489  0
         return result;
 490  
     }
 491  
     
 492  
     private List<ArchivaRepositoryMetadata> getMetadatasForManagedRepository( ManagedRepositoryContent managedRepository, String logicalResource )
 493  
     {
 494  0
         List<ArchivaRepositoryMetadata> metadatas = new ArrayList<ArchivaRepositoryMetadata>();
 495  0
         File file = new File(managedRepository.getRepoRoot(), logicalResource);
 496  0
         if (file.exists())
 497  
         {
 498  
             try
 499  
             {
 500  0
                ArchivaRepositoryMetadata existingMetadata = RepositoryMetadataReader.read(file);
 501  0
                if (existingMetadata != null)
 502  
                {
 503  0
                     metadatas.add(existingMetadata);
 504  
                }
 505  
             }
 506  0
             catch (RepositoryMetadataException e)
 507  
             {
 508  0
                 log.debug("Could not read metadata at " + file.getAbsolutePath() + ". Metadata will be removed.");
 509  0
                 FileUtils.deleteQuietly(file);
 510  0
             }
 511  
         }
 512  
         
 513  0
         Set<String> proxyIds = proxies.get(managedRepository.getId());
 514  0
         if (proxyIds != null)
 515  
         {
 516  0
             for (String proxyId : proxyIds)
 517  
             {
 518  0
                 ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, logicalResource, proxyId );
 519  0
                 if (proxyMetadata != null)
 520  
                 {
 521  0
                     metadatas.add(proxyMetadata);
 522  
                 }
 523  0
             }
 524  
         }
 525  
         
 526  0
         return metadatas;
 527  
     }
 528  
     
 529  
 
 530  
     /**
 531  
      * Update the metadata to represent the all versions/plugins of
 532  
      * the provided groupId:artifactId project or group reference,
 533  
      * based off of information present in the repository,
 534  
      * the maven-metadata.xml files, and the proxy/repository specific
 535  
      * metadata file contents.
 536  
      *
 537  
      * We must treat this as a group or a project metadata file as there is no way to know in advance
 538  
      *
 539  
      * @deprecated 
 540  
      * @param managedRepository the managed repository where the metadata is kept.
 541  
      * @param reference         the reference to update.
 542  
      * @throws LayoutException
 543  
      * @throws RepositoryMetadataException
 544  
      * @throws IOException
 545  
      * @throws ContentNotFoundException 
 546  
      */
 547  
     public void updateMetadata( ManagedRepositoryContent managedRepository, ProjectReference reference )
 548  
         throws LayoutException, RepositoryMetadataException, IOException, ContentNotFoundException
 549  
     {
 550  0
         File metadataFile = new File( managedRepository.getRepoRoot(), toPath( reference ) );
 551  
 
 552  0
         long lastUpdated = getExistingLastUpdated( metadataFile );
 553  
 
 554  0
         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
 555  0
         metadata.setGroupId( reference.getGroupId() );
 556  0
         metadata.setArtifactId( reference.getArtifactId() );
 557  
 
 558  
         // Gather up all versions found in the managed repository.
 559  0
         Set<String> allVersions = managedRepository.getVersions( reference );
 560  
 
 561  
         // Gather up all plugins found in the managed repository.
 562  
         // TODO: do we know this information instead?
 563  
 //        Set<Plugin> allPlugins = managedRepository.getPlugins( reference );
 564  
         Set<Plugin> allPlugins;
 565  0
         if ( metadataFile.exists() )
 566  
         {
 567  0
             allPlugins = new LinkedHashSet<Plugin>( RepositoryMetadataReader.read( metadataFile ).getPlugins() );
 568  
         }
 569  
         else
 570  
         {
 571  0
             allPlugins = new LinkedHashSet<Plugin>();
 572  
         }
 573  
 
 574  
         // Does this repository have a set of remote proxied repositories?
 575  0
         Set<String> proxiedRepoIds = this.proxies.get( managedRepository.getId() );
 576  
 
 577  0
         if ( CollectionUtils.isNotEmpty( proxiedRepoIds ) )
 578  
         {
 579  
             // Add in the proxied repo version ids too.
 580  0
             Iterator<String> it = proxiedRepoIds.iterator();
 581  0
             while ( it.hasNext() )
 582  
             {
 583  0
                 String proxyId = it.next();
 584  
 
 585  0
                 ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, reference, proxyId );
 586  0
                 if ( proxyMetadata != null )
 587  
                 {
 588  0
                     allVersions.addAll( proxyMetadata.getAvailableVersions() );
 589  0
                     allPlugins.addAll( proxyMetadata.getPlugins() );
 590  0
                     long proxyLastUpdated = getLastUpdated( proxyMetadata );
 591  
 
 592  0
                     lastUpdated = Math.max( lastUpdated, proxyLastUpdated );
 593  
                 }
 594  0
             }
 595  
         }
 596  
 
 597  0
         if ( !allVersions.isEmpty() )
 598  
         {
 599  0
             updateMetadataVersions( allVersions ,metadata );
 600  
         }
 601  
         else
 602  
         {
 603  
             // Add the plugins to the metadata model.
 604  0
             metadata.setPlugins( new ArrayList<Plugin>( allPlugins ) );
 605  
 
 606  
             // artifact ID was actually the last part of the group
 607  0
             metadata.setGroupId( metadata.getGroupId() + "." + metadata.getArtifactId() );
 608  0
             metadata.setArtifactId( null );
 609  
         }
 610  
 
 611  0
         if ( lastUpdated > 0 )
 612  
         {
 613  0
             metadata.setLastUpdatedTimestamp( toLastUpdatedDate( lastUpdated ) );
 614  
         }
 615  
 
 616  
         // Save the metadata model to disk.
 617  0
         RepositoryMetadataWriter.write( metadata, metadataFile );
 618  0
         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
 619  0
         checksum.fixChecksums( algorithms );
 620  0
     }
 621  
 
 622  
     private void updateMetadataVersions(Collection<String> allVersions, ArchivaRepositoryMetadata metadata) 
 623  
     {
 624  
         // Sort the versions
 625  0
         List<String> sortedVersions = new ArrayList<String>(allVersions);
 626  0
         Collections.sort(sortedVersions, VersionComparator.getInstance());
 627  
 
 628  
         // Split the versions into released and snapshots.
 629  0
         List<String> releasedVersions = new ArrayList<String>();
 630  0
         List<String> snapshotVersions = new ArrayList<String>();
 631  
 
 632  0
         for (String version : sortedVersions) 
 633  
         {
 634  0
             if (VersionUtil.isSnapshot(version)) 
 635  
             {
 636  0
                 snapshotVersions.add(version);
 637  
             }
 638  
             else 
 639  
             {
 640  0
                 releasedVersions.add(version);
 641  
             }
 642  
         }
 643  
 
 644  0
         Collections.sort(releasedVersions, VersionComparator.getInstance());
 645  0
         Collections.sort(snapshotVersions, VersionComparator.getInstance());
 646  
 
 647  0
         String latestVersion = sortedVersions.get(sortedVersions.size() - 1);
 648  0
         String releaseVersion = null;
 649  
 
 650  0
         if (CollectionUtils.isNotEmpty(releasedVersions)) 
 651  
         {
 652  0
             releaseVersion = releasedVersions.get(releasedVersions.size() - 1);
 653  
         }
 654  
 
 655  
         // Add the versions to the metadata model.
 656  0
         metadata.setAvailableVersions(sortedVersions);
 657  
 
 658  0
         metadata.setLatestVersion(latestVersion);
 659  0
         metadata.setReleasedVersion(releaseVersion);
 660  0
     }
 661  
 
 662  
     private Date toLastUpdatedDate( long lastUpdated )
 663  
     {
 664  0
         Calendar cal = Calendar.getInstance( DateUtils.UTC_TIME_ZONE );
 665  0
         cal.setTimeInMillis( lastUpdated );
 666  
 
 667  0
         return cal.getTime();
 668  
     }
 669  
     
 670  
     private long toLastUpdatedLong( String timestampString )
 671  
     {
 672  
         try
 673  
         {
 674  0
             Date date = lastUpdatedFormat.parse( timestampString );
 675  0
             Calendar cal = Calendar.getInstance( DateUtils.UTC_TIME_ZONE );
 676  0
             cal.setTime( date );
 677  
 
 678  0
             return cal.getTimeInMillis();
 679  
         }
 680  0
         catch ( ParseException e )
 681  
         {
 682  0
             return 0;
 683  
         }
 684  
     }
 685  
 
 686  
     private long getLastUpdated( ArchivaRepositoryMetadata metadata )
 687  
     {
 688  0
         if ( metadata == null )
 689  
         {
 690  
             // Doesn't exist.
 691  0
             return 0;
 692  
         }
 693  
 
 694  
         try
 695  
         {
 696  0
             String lastUpdated = metadata.getLastUpdated();
 697  0
             if ( StringUtils.isBlank( lastUpdated ) )
 698  
             {
 699  
                 // Not set.
 700  0
                 return 0;
 701  
             }
 702  
 
 703  0
             Date lastUpdatedDate = lastUpdatedFormat.parse( lastUpdated );
 704  0
             return lastUpdatedDate.getTime();
 705  
         }
 706  0
         catch ( ParseException e )
 707  
         {
 708  
             // Bad format on the last updated string.
 709  0
             return 0;
 710  
         }
 711  
     }
 712  
 
 713  
     private long getExistingLastUpdated( File metadataFile )
 714  
     {
 715  0
         if ( !metadataFile.exists() )
 716  
         {
 717  
             // Doesn't exist.
 718  0
             return 0;
 719  
         }
 720  
 
 721  
         try
 722  
         {
 723  0
             ArchivaRepositoryMetadata metadata = RepositoryMetadataReader.read( metadataFile );
 724  
 
 725  0
             return getLastUpdated( metadata );
 726  
         }
 727  0
         catch ( RepositoryMetadataException e )
 728  
         {
 729  
             // Error.
 730  0
             return 0;
 731  
         }
 732  
     }
 733  
 
 734  
     /**
 735  
      * Update the metadata based on the following rules.
 736  
      * <p/>
 737  
      * 1) If this is a SNAPSHOT reference, then utilize the proxy/repository specific
 738  
      * metadata files to represent the current / latest SNAPSHOT available.
 739  
      * 2) If this is a RELEASE reference, and the metadata file does not exist, then
 740  
      * create the metadata file with contents required of the VersionedReference
 741  
      *
 742  
      * @deprecated
 743  
      * @param managedRepository the managed repository where the metadata is kept.
 744  
      * @param reference         the versioned reference to update
 745  
      * @throws LayoutException
 746  
      * @throws RepositoryMetadataException
 747  
      * @throws IOException
 748  
      * @throws ContentNotFoundException 
 749  
      */
 750  
     public void updateMetadata( ManagedRepositoryContent managedRepository, VersionedReference reference )
 751  
         throws LayoutException, RepositoryMetadataException, IOException, ContentNotFoundException
 752  
     {
 753  0
         File metadataFile = new File( managedRepository.getRepoRoot(), toPath( reference ) );
 754  
 
 755  0
         long lastUpdated = getExistingLastUpdated( metadataFile );
 756  
 
 757  0
         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
 758  0
         metadata.setGroupId( reference.getGroupId() );
 759  0
         metadata.setArtifactId( reference.getArtifactId() );
 760  
         
 761  0
         if ( VersionUtil.isSnapshot( reference.getVersion() ) )
 762  
         {
 763  
             // Do SNAPSHOT handling.
 764  0
             metadata.setVersion( VersionUtil.getBaseVersion( reference.getVersion() ) );
 765  
 
 766  
             // Gather up all of the versions found in the reference dir, and any
 767  
             // proxied maven-metadata.xml files.
 768  0
             Set<String> snapshotVersions = gatherSnapshotVersions( managedRepository, reference );
 769  
 
 770  0
             if ( snapshotVersions.isEmpty() )
 771  
             {
 772  0
                 throw new ContentNotFoundException( "No snapshot versions found on reference ["
 773  
                     + VersionedReference.toKey( reference ) + "]." );
 774  
             }
 775  
 
 776  
             // sort the list to determine to aide in determining the Latest version.
 777  0
             List<String> sortedVersions = new ArrayList<String>();
 778  0
             sortedVersions.addAll( snapshotVersions );
 779  0
             Collections.sort( sortedVersions, new VersionComparator() );
 780  
 
 781  0
             String latestVersion = sortedVersions.get( sortedVersions.size() - 1 );
 782  
 
 783  0
             if ( VersionUtil.isUniqueSnapshot( latestVersion ) )
 784  
             {
 785  
                 // The latestVersion will contain the full version string "1.0-alpha-5-20070821.213044-8"
 786  
                 // This needs to be broken down into ${base}-${timestamp}-${build_number}
 787  
 
 788  0
                 Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( latestVersion );
 789  0
                 if ( m.matches() )
 790  
                 {
 791  0
                     metadata.setSnapshotVersion( new SnapshotVersion() );
 792  0
                     int buildNumber = NumberUtils.toInt( m.group( 3 ), -1 );
 793  0
                     metadata.getSnapshotVersion().setBuildNumber( buildNumber );
 794  
 
 795  0
                     Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) );
 796  0
                     if ( mtimestamp.matches() )
 797  
                     {
 798  0
                         String tsDate = mtimestamp.group( 1 );
 799  0
                         String tsTime = mtimestamp.group( 2 );
 800  
                         
 801  0
                         long snapshotLastUpdated = toLastUpdatedLong( tsDate + tsTime );
 802  
                         
 803  0
                         lastUpdated = Math.max( lastUpdated, snapshotLastUpdated );
 804  
                         
 805  0
                         metadata.getSnapshotVersion().setTimestamp( m.group( 2 ) );
 806  
                     }
 807  
                 }
 808  0
             }
 809  0
             else if ( VersionUtil.isGenericSnapshot( latestVersion ) )
 810  
             {
 811  
                 // The latestVersion ends with the generic version string.
 812  
                 // Example: 1.0-alpha-5-SNAPSHOT
 813  
 
 814  0
                 metadata.setSnapshotVersion( new SnapshotVersion() );
 815  
 
 816  
                 /* Disabled due to decision in [MRM-535].
 817  
                  * Do not set metadata.lastUpdated to file.lastModified.
 818  
                  * 
 819  
                  * Should this be the last updated timestamp of the file, or in the case of an 
 820  
                  * archive, the most recent timestamp in the archive?
 821  
                  * 
 822  
                 ArtifactReference artifact = getFirstArtifact( managedRepository, reference );
 823  
 
 824  
                 if ( artifact == null )
 825  
                 {
 826  
                     throw new IOException( "Not snapshot artifact found to reference in " + reference );
 827  
                 }
 828  
 
 829  
                 File artifactFile = managedRepository.toFile( artifact );
 830  
 
 831  
                 if ( artifactFile.exists() )
 832  
                 {
 833  
                     Date lastModified = new Date( artifactFile.lastModified() );
 834  
                     metadata.setLastUpdatedTimestamp( lastModified );
 835  
                 }
 836  
                 */
 837  
             }
 838  
             else
 839  
             {
 840  0
                 throw new RepositoryMetadataException( "Unable to process snapshot version <" + latestVersion
 841  
                     + "> reference <" + reference + ">" );
 842  
             }
 843  0
         }
 844  
         else
 845  
         {
 846  
             // Do RELEASE handling.
 847  0
             metadata.setVersion( reference.getVersion() );
 848  
         }
 849  
 
 850  
         // Set last updated
 851  0
         if ( lastUpdated > 0 )
 852  
         {
 853  0
             metadata.setLastUpdatedTimestamp( toLastUpdatedDate( lastUpdated ) );
 854  
         }
 855  
 
 856  
         // Save the metadata model to disk.
 857  0
         RepositoryMetadataWriter.write( metadata, metadataFile );
 858  0
         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
 859  0
         checksum.fixChecksums( algorithms );
 860  0
     }
 861  
 
 862  
     private void initConfigVariables()
 863  
     {
 864  0
         synchronized ( this.artifactPatterns )
 865  
         {
 866  0
             this.artifactPatterns.clear();
 867  
 
 868  0
             this.artifactPatterns.addAll( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) );
 869  0
         }
 870  
 
 871  0
         synchronized ( proxies )
 872  
         {
 873  0
             this.proxies.clear();
 874  
 
 875  0
             List<ProxyConnectorConfiguration> proxyConfigs = configuration.getConfiguration().getProxyConnectors();
 876  0
             for( ProxyConnectorConfiguration proxyConfig: proxyConfigs )
 877  
             {
 878  0
                 String key = proxyConfig.getSourceRepoId();
 879  
 
 880  0
                 Set<String> remoteRepoIds = this.proxies.get( key );
 881  
 
 882  0
                 if ( remoteRepoIds == null )
 883  
                 {
 884  0
                     remoteRepoIds = new HashSet<String>();
 885  
                 }
 886  
 
 887  0
                 remoteRepoIds.add( proxyConfig.getTargetRepoId() );
 888  
 
 889  0
                 this.proxies.put( key, remoteRepoIds );
 890  0
             }
 891  0
         }
 892  0
     }
 893  
 
 894  
     /**
 895  
      * Get the first Artifact found in the provided VersionedReference location.
 896  
      *
 897  
      * @param managedRepository the repository to search within.
 898  
      * @param reference         the reference to the versioned reference to search within
 899  
      * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
 900  
      *         no artifact was found within the versioned reference.
 901  
      * @throws IOException     if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
 902  
      * @throws LayoutException
 903  
      */
 904  
     public ArtifactReference getFirstArtifact( ManagedRepositoryContent managedRepository, VersionedReference reference )
 905  
         throws LayoutException, IOException
 906  
     {
 907  0
         String path = toPath( reference );
 908  
 
 909  0
         int idx = path.lastIndexOf( '/' );
 910  0
         if ( idx > 0 )
 911  
         {
 912  0
             path = path.substring( 0, idx );
 913  
         }
 914  
 
 915  0
         File repoDir = new File( managedRepository.getRepoRoot(), path );
 916  
 
 917  0
         if ( !repoDir.exists() )
 918  
         {
 919  0
             throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
 920  
                 + repoDir.getAbsolutePath() );
 921  
         }
 922  
 
 923  0
         if ( !repoDir.isDirectory() )
 924  
         {
 925  0
             throw new IOException( "Unable to gather the list of snapshot versions on a non-directory: "
 926  
                 + repoDir.getAbsolutePath() );
 927  
         }
 928  
 
 929  0
         File repoFiles[] = repoDir.listFiles();
 930  0
         for ( int i = 0; i < repoFiles.length; i++ )
 931  
         {
 932  0
             if ( repoFiles[i].isDirectory() )
 933  
             {
 934  
                 // Skip it. it's a directory.
 935  0
                 continue;
 936  
             }
 937  
 
 938  0
             String relativePath = PathUtil.getRelative( managedRepository.getRepoRoot(), repoFiles[i] );
 939  
 
 940  0
             if ( filetypes.matchesArtifactPattern( relativePath ) )
 941  
             {
 942  0
                 ArtifactReference artifact = managedRepository.toArtifactReference( relativePath );
 943  
 
 944  0
                 return artifact;
 945  
             }
 946  
         }
 947  
 
 948  
         // No artifact was found.
 949  0
         return null;
 950  
     }
 951  
 }