Coverage Report - org.apache.maven.artifact.repository.metadata.DefaultRepositoryMetadataManager
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultRepositoryMetadataManager
13 %
19/148
3 %
2/68
6,5
 
 1  
 package org.apache.maven.artifact.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.maven.artifact.manager.WagonManager;
 23  
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 24  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 25  
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 26  
 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
 27  
 import org.apache.maven.wagon.ResourceDoesNotExistException;
 28  
 import org.apache.maven.wagon.TransferFailedException;
 29  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 30  
 import org.codehaus.plexus.util.IOUtil;
 31  
 import org.codehaus.plexus.util.ReaderFactory;
 32  
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 33  
 
 34  
 import java.io.File;
 35  
 import java.io.FileNotFoundException;
 36  
 import java.io.IOException;
 37  
 import java.io.Reader;
 38  
 import java.util.Date;
 39  
 import java.util.HashMap;
 40  
 import java.util.HashSet;
 41  
 import java.util.Iterator;
 42  
 import java.util.List;
 43  
 import java.util.Map;
 44  
 import java.util.Set;
 45  
 
 46  13
 public class DefaultRepositoryMetadataManager
 47  
     extends AbstractLogEnabled
 48  
     implements RepositoryMetadataManager
 49  
 {
 50  
     // component requirement
 51  
     private WagonManager wagonManager;
 52  
 
 53  
     /**
 54  
      * @todo very primitive. Probably we can cache artifacts themselves in a central location, as well as reset the flag over time in a long running process.
 55  
      */
 56  13
     private Set cachedMetadata = new HashSet();
 57  
 
 58  
     public void resolve( RepositoryMetadata metadata, List remoteRepositories, ArtifactRepository localRepository )
 59  
         throws RepositoryMetadataResolutionException
 60  
     {
 61  0
         boolean alreadyResolved = alreadyResolved( metadata );
 62  0
         if ( !alreadyResolved )
 63  
         {
 64  0
             for ( Iterator i = remoteRepositories.iterator(); i.hasNext(); )
 65  
             {
 66  0
                 ArtifactRepository repository = (ArtifactRepository) i.next();
 67  
 
 68  0
                 ArtifactRepositoryPolicy policy =
 69  
                     metadata.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
 70  
 
 71  0
                 if ( !policy.isEnabled() )
 72  
                 {
 73  0
                     getLogger().debug( "Skipping disabled repository " + repository.getId() );
 74  
                 }
 75  0
                 else if ( repository.isBlacklisted() )
 76  
                 {
 77  0
                     getLogger().debug( "Skipping blacklisted repository " + repository.getId() );
 78  
                 }
 79  
                 else
 80  
                 {
 81  0
                     File file = new File( localRepository.getBasedir(),
 82  
                                           localRepository.pathOfLocalRepositoryMetadata( metadata, repository ) );
 83  
 
 84  
 
 85  0
                     boolean checkForUpdates =
 86  
                         !file.exists() || policy.checkOutOfDate( new Date( file.lastModified() ) );
 87  
 
 88  0
                     if ( checkForUpdates )
 89  
                     {
 90  0
                         if ( wagonManager.isOnline() )
 91  
                         {
 92  0
                             getLogger().info( metadata.getKey() + ": checking for updates from " + repository.getId() );
 93  
 
 94  0
                             boolean storeMetadata = false;
 95  
                             try
 96  
                             {
 97  0
                                 wagonManager.getArtifactMetadata( metadata, repository, file,
 98  
                                                                   policy.getChecksumPolicy() );
 99  0
                                 storeMetadata = true;
 100  
                             }
 101  0
                             catch ( ResourceDoesNotExistException e )
 102  
                             {
 103  0
                                 getLogger().debug(
 104  
                                     metadata + " could not be found on repository: " + repository.getId() );
 105  
 
 106  
                                 // delete the local copy so the old details aren't used.
 107  0
                                 if ( file.exists() )
 108  
                                 {
 109  0
                                     file.delete();
 110  
                                 }
 111  0
                                 storeMetadata = true;
 112  
                             }
 113  0
                             catch ( TransferFailedException e )
 114  
                             {
 115  0
                                 getLogger().warn( metadata + " could not be retrieved from repository: " +
 116  
                                     repository.getId() + " due to an error: " + e.getMessage() );
 117  0
                                 getLogger().debug( "Exception", e );
 118  
 
 119  0
                                 getLogger().info( "Repository '" + repository.getId() + "' will be blacklisted" );
 120  0
                                 repository.setBlacklisted( true );
 121  
 
 122  
                                 // TODO: [jc; 08-Nov-2005] revisit this for 2.1
 123  
                                 // suppressing logging to avoid logging this error twice.
 124  0
                             }
 125  0
                             if ( storeMetadata )
 126  
                             {
 127  
                                 // touch file so that this is not checked again until interval has passed
 128  0
                                 if ( file.exists() )
 129  
                                 {
 130  0
                                     file.setLastModified( System.currentTimeMillis() );
 131  
                                 }
 132  
                                 else
 133  
                                 {
 134  
                                     // this ensures that files are not continuously checked when they don't exist remotely
 135  
 
 136  
                                     // TODO: [jdcasey] If this happens as a result of ResourceDoesNotExistException, what effect will it have on subsequent runs?
 137  
                                     // Will the updateInterval come into play cleanly, or will this plug up the works??
 138  
                                     try
 139  
                                     {
 140  0
                                         metadata.storeInLocalRepository( localRepository, repository );
 141  
                                     }
 142  0
                                     catch ( RepositoryMetadataStoreException e )
 143  
                                     {
 144  0
                                         throw new RepositoryMetadataResolutionException(
 145  
                                             "Unable to store local copy of metadata: " + e.getMessage(), e );
 146  0
                                     }
 147  
                                 }
 148  
                             }
 149  0
                         }
 150  
                         else
 151  
                         {
 152  0
                             getLogger().debug( "System is offline. Cannot resolve metadata:\n" +
 153  
                                 metadata.extendedToString() + "\n\n" );
 154  
                         }
 155  
                     }
 156  
                 }
 157  0
             }
 158  
 
 159  
             // TODO: [jdcasey] what happens here when the system is offline, or there is a TransferFailedException
 160  
             // ...and no metadata file is written?
 161  0
             cachedMetadata.add( metadata.getKey() );
 162  
         }
 163  
 
 164  
         try
 165  
         {
 166  0
             mergeMetadata( metadata, remoteRepositories, localRepository );
 167  
         }
 168  0
         catch ( RepositoryMetadataStoreException e )
 169  
         {
 170  0
             throw new RepositoryMetadataResolutionException(
 171  
                 "Unable to store local copy of metadata: " + e.getMessage(), e );
 172  
         }
 173  0
         catch ( RepositoryMetadataReadException e )
 174  
         {
 175  0
             throw new RepositoryMetadataResolutionException( "Unable to read local copy of metadata: " + e.getMessage(),
 176  
                                                              e );
 177  0
         }
 178  0
     }
 179  
 
 180  
     private void mergeMetadata( RepositoryMetadata metadata, List remoteRepositories,
 181  
                                 ArtifactRepository localRepository )
 182  
         throws RepositoryMetadataStoreException, RepositoryMetadataReadException
 183  
     {
 184  
         // TODO: currently this is first wins, but really we should take the latest by comparing either the
 185  
         // snapshot timestamp, or some other timestamp later encoded into the metadata.
 186  
         // TODO: this needs to be repeated here so the merging doesn't interfere with the written metadata
 187  
         //  - we'd be much better having a pristine input, and an ongoing metadata for merging instead
 188  
 
 189  0
         Map previousMetadata = new HashMap();
 190  0
         ArtifactRepository selected = null;
 191  0
         for ( Iterator i = remoteRepositories.iterator(); i.hasNext(); )
 192  
         {
 193  0
             ArtifactRepository repository = (ArtifactRepository) i.next();
 194  
 
 195  0
             ArtifactRepositoryPolicy policy =
 196  
                 metadata.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
 197  
 
 198  0
             if ( policy.isEnabled() && loadMetadata( metadata, repository, localRepository, previousMetadata ) )
 199  
             {
 200  0
                 metadata.setRepository( repository );
 201  0
                 selected = repository;
 202  
             }
 203  0
         }
 204  0
         if ( loadMetadata( metadata, localRepository, localRepository, previousMetadata ) )
 205  
         {
 206  0
             metadata.setRepository( null );
 207  0
             selected = localRepository;
 208  
         }
 209  
 
 210  0
         updateSnapshotMetadata( metadata, previousMetadata, selected, localRepository );
 211  0
     }
 212  
 
 213  
     private void updateSnapshotMetadata( RepositoryMetadata metadata, Map previousMetadata, ArtifactRepository selected,
 214  
                                          ArtifactRepository localRepository )
 215  
         throws RepositoryMetadataStoreException
 216  
     {
 217  
         // TODO: this could be a lot nicer... should really be in the snapshot transformation?
 218  0
         if ( metadata.isSnapshot() )
 219  
         {
 220  0
             Metadata prevMetadata = metadata.getMetadata();
 221  
 
 222  0
             for ( Iterator i = previousMetadata.keySet().iterator(); i.hasNext(); )
 223  
             {
 224  0
                 ArtifactRepository repository = (ArtifactRepository) i.next();
 225  0
                 Metadata m = (Metadata) previousMetadata.get( repository );
 226  0
                 if ( repository.equals( selected ) )
 227  
                 {
 228  0
                     if ( m.getVersioning() == null )
 229  
                     {
 230  0
                         m.setVersioning( new Versioning() );
 231  
                     }
 232  
 
 233  0
                     if ( m.getVersioning().getSnapshot() == null )
 234  
                     {
 235  0
                         m.getVersioning().setSnapshot( new Snapshot() );
 236  
                     }
 237  
 /*
 238  
                     if ( !m.getVersioning().getSnapshot().isLocalCopy() )
 239  
                     {
 240  
                         // TODO: I think this is incorrect (it results in localCopy set in a remote profile). Probably
 241  
                         //   harmless so not removing at this point until full tests in place.
 242  
                         m.getVersioning().getSnapshot().setLocalCopy( true );
 243  
                         metadata.setMetadata( m );
 244  
                         metadata.storeInLocalRepository( localRepository, repository );
 245  
                     }
 246  
 */
 247  
                 }
 248  
                 else
 249  
                 {
 250  0
                     if ( ( m.getVersioning() != null ) && ( m.getVersioning().getSnapshot() != null ) &&
 251  
                         m.getVersioning().getSnapshot().isLocalCopy() )
 252  
                     {
 253  0
                         m.getVersioning().getSnapshot().setLocalCopy( false );
 254  0
                         metadata.setMetadata( m );
 255  0
                         metadata.storeInLocalRepository( localRepository, repository );
 256  
                     }
 257  
                 }
 258  0
             }
 259  
 
 260  0
             metadata.setMetadata( prevMetadata );
 261  
         }
 262  0
     }
 263  
 
 264  
     private boolean loadMetadata( RepositoryMetadata repoMetadata, ArtifactRepository remoteRepository,
 265  
                                   ArtifactRepository localRepository, Map previousMetadata )
 266  
         throws RepositoryMetadataReadException
 267  
     {
 268  0
         boolean setRepository = false;
 269  
 
 270  0
         File metadataFile = new File( localRepository.getBasedir(),
 271  
                                       localRepository.pathOfLocalRepositoryMetadata( repoMetadata, remoteRepository ) );
 272  
 
 273  0
         if ( metadataFile.exists() )
 274  
         {
 275  0
             Metadata metadata = readMetadata( metadataFile );
 276  
 
 277  0
             if ( repoMetadata.isSnapshot() && ( previousMetadata != null ) )
 278  
             {
 279  0
                 previousMetadata.put( remoteRepository, metadata );
 280  
             }
 281  
 
 282  0
             if ( repoMetadata.getMetadata() != null )
 283  
             {
 284  0
                 setRepository = repoMetadata.getMetadata().merge( metadata );
 285  
             }
 286  
             else
 287  
             {
 288  0
                 repoMetadata.setMetadata( metadata );
 289  0
                 setRepository = true;
 290  
             }
 291  
         }
 292  0
         return setRepository;
 293  
     }
 294  
 
 295  
     /**
 296  
      * @todo share with DefaultPluginMappingManager.
 297  
      */
 298  
     protected static Metadata readMetadata( File mappingFile )
 299  
         throws RepositoryMetadataReadException
 300  
     {
 301  
         Metadata result;
 302  
 
 303  0
         Reader reader = null;
 304  
         try
 305  
         {
 306  0
             reader = ReaderFactory.newXmlReader( mappingFile );
 307  
 
 308  0
             MetadataXpp3Reader mappingReader = new MetadataXpp3Reader();
 309  
 
 310  0
             result = mappingReader.read( reader, false );
 311  
         }
 312  0
         catch ( FileNotFoundException e )
 313  
         {
 314  0
             throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "'", e );
 315  
         }
 316  0
         catch ( IOException e )
 317  
         {
 318  0
             throw new RepositoryMetadataReadException(
 319  
                 "Cannot read metadata from '" + mappingFile + "': " + e.getMessage(), e );
 320  
         }
 321  0
         catch ( XmlPullParserException e )
 322  
         {
 323  0
             throw new RepositoryMetadataReadException(
 324  
                 "Cannot read metadata from '" + mappingFile + "': " + e.getMessage(), e );
 325  
         }
 326  
         finally
 327  
         {
 328  0
             IOUtil.close( reader );
 329  0
         }
 330  0
         return result;
 331  
     }
 332  
 
 333  
     public void resolveAlways( RepositoryMetadata metadata, ArtifactRepository localRepository,
 334  
                                ArtifactRepository remoteRepository )
 335  
         throws RepositoryMetadataResolutionException
 336  
     {
 337  0
         if ( !wagonManager.isOnline() )
 338  
         {
 339  
             // metadata is required for deployment, can't be offline
 340  0
             throw new RepositoryMetadataResolutionException(
 341  
                 "System is offline. Cannot resolve required metadata:\n" + metadata.extendedToString() );
 342  
         }
 343  
 
 344  
         File file;
 345  
         try
 346  
         {
 347  0
             file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, remoteRepository );
 348  
         }
 349  0
         catch ( TransferFailedException e )
 350  
         {
 351  0
             throw new RepositoryMetadataResolutionException( metadata + " could not be retrieved from repository: " +
 352  
                 remoteRepository.getId() + " due to an error: " + e.getMessage(), e );
 353  0
         }
 354  
 
 355  
         try
 356  
         {
 357  0
             if ( file.exists() )
 358  
             {
 359  0
                 Metadata prevMetadata = readMetadata( file );
 360  0
                 metadata.setMetadata( prevMetadata );
 361  
             }
 362  
         }
 363  0
         catch ( RepositoryMetadataReadException e )
 364  
         {
 365  0
             throw new RepositoryMetadataResolutionException( e.getMessage(), e );
 366  0
         }
 367  0
     }
 368  
 
 369  
     private File getArtifactMetadataFromDeploymentRepository( ArtifactMetadata metadata,
 370  
                                                               ArtifactRepository localRepository,
 371  
                                                               ArtifactRepository remoteRepository )
 372  
         throws TransferFailedException
 373  
     {
 374  1
         File file = new File( localRepository.getBasedir(),
 375  
                               localRepository.pathOfLocalRepositoryMetadata( metadata, remoteRepository ) );
 376  
 
 377  
         try
 378  
         {
 379  1
             wagonManager.getArtifactMetadataFromDeploymentRepository( metadata, remoteRepository, file,
 380  
                                                                       ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
 381  
         }
 382  0
         catch ( ResourceDoesNotExistException e )
 383  
         {
 384  0
             getLogger().info(
 385  
                 metadata + " could not be found on repository: " + remoteRepository.getId() + ", so will be created" );
 386  
 
 387  
             // delete the local copy so the old details aren't used.
 388  0
             if ( file.exists() )
 389  
             {
 390  0
                 file.delete();
 391  
             }
 392  1
         }
 393  1
         return file;
 394  
     }
 395  
 
 396  
     private boolean alreadyResolved( ArtifactMetadata metadata )
 397  
     {
 398  0
         return cachedMetadata.contains( metadata.getKey() );
 399  
     }
 400  
 
 401  
     public void deploy( ArtifactMetadata metadata, ArtifactRepository localRepository,
 402  
                         ArtifactRepository deploymentRepository )
 403  
         throws RepositoryMetadataDeploymentException
 404  
     {
 405  1
         if ( !wagonManager.isOnline() )
 406  
         {
 407  
             // deployment shouldn't silently fail when offline
 408  0
             throw new RepositoryMetadataDeploymentException(
 409  
                 "System is offline. Cannot deploy metadata:\n" + metadata.extendedToString() );
 410  
         }
 411  
 
 412  
         File file;
 413  1
         if ( metadata instanceof RepositoryMetadata )
 414  
         {
 415  1
             getLogger().info( "Retrieving previous metadata from " + deploymentRepository.getId() );
 416  
             try
 417  
             {
 418  1
                 file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, deploymentRepository );
 419  
             }
 420  0
             catch ( TransferFailedException e )
 421  
             {
 422  0
                 throw new RepositoryMetadataDeploymentException( metadata +
 423  
                     " could not be retrieved from repository: " + deploymentRepository.getId() + " due to an error: " +
 424  
                     e.getMessage(), e );
 425  1
             }
 426  
         }
 427  
         else
 428  
         {
 429  
             // It's a POM - we don't need to retrieve it first
 430  0
             file = new File( localRepository.getBasedir(),
 431  
                              localRepository.pathOfLocalRepositoryMetadata( metadata, deploymentRepository ) );
 432  
         }
 433  
 
 434  
         try
 435  
         {
 436  1
             metadata.storeInLocalRepository( localRepository, deploymentRepository );
 437  
         }
 438  0
         catch ( RepositoryMetadataStoreException e )
 439  
         {
 440  0
             throw new RepositoryMetadataDeploymentException( "Error installing metadata: " + e.getMessage(), e );
 441  1
         }
 442  
 
 443  
         try
 444  
         {
 445  1
             wagonManager.putArtifactMetadata( file, metadata, deploymentRepository );
 446  
         }
 447  0
         catch ( TransferFailedException e )
 448  
         {
 449  0
             throw new RepositoryMetadataDeploymentException( "Error while deploying metadata: " + e.getMessage(), e );
 450  1
         }
 451  1
     }
 452  
 
 453  
     public void install( ArtifactMetadata metadata, ArtifactRepository localRepository )
 454  
         throws RepositoryMetadataInstallationException
 455  
     {
 456  
         try
 457  
         {
 458  1
             metadata.storeInLocalRepository( localRepository, localRepository );
 459  
         }
 460  0
         catch ( RepositoryMetadataStoreException e )
 461  
         {
 462  0
             throw new RepositoryMetadataInstallationException( "Error installing metadata: " + e.getMessage(), e );
 463  1
         }
 464  1
     }
 465  
 }