001package org.eclipse.aether.internal.impl; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import static java.util.Objects.requireNonNull; 023 024import java.io.File; 025import java.io.InputStream; 026import java.util.ArrayList; 027import java.util.Collection; 028import java.util.IdentityHashMap; 029import java.util.List; 030import java.util.ListIterator; 031import java.util.Set; 032 033import javax.inject.Inject; 034import javax.inject.Named; 035import javax.inject.Singleton; 036 037import org.eclipse.aether.RepositoryEvent; 038import org.eclipse.aether.RepositoryEvent.EventType; 039import org.eclipse.aether.RepositorySystemSession; 040import org.eclipse.aether.RequestTrace; 041import org.eclipse.aether.SyncContext; 042import org.eclipse.aether.artifact.Artifact; 043import org.eclipse.aether.impl.Installer; 044import org.eclipse.aether.impl.MetadataGenerator; 045import org.eclipse.aether.impl.MetadataGeneratorFactory; 046import org.eclipse.aether.impl.RepositoryEventDispatcher; 047import org.eclipse.aether.spi.synccontext.SyncContextFactory; 048import org.eclipse.aether.installation.InstallRequest; 049import org.eclipse.aether.installation.InstallResult; 050import org.eclipse.aether.installation.InstallationException; 051import org.eclipse.aether.metadata.MergeableMetadata; 052import org.eclipse.aether.metadata.Metadata; 053import org.eclipse.aether.repository.LocalArtifactRegistration; 054import org.eclipse.aether.repository.LocalMetadataRegistration; 055import org.eclipse.aether.repository.LocalRepositoryManager; 056import org.eclipse.aether.spi.io.FileProcessor; 057import org.eclipse.aether.spi.locator.Service; 058import org.eclipse.aether.spi.locator.ServiceLocator; 059import org.eclipse.aether.transform.FileTransformer; 060import org.slf4j.Logger; 061import org.slf4j.LoggerFactory; 062 063/** 064 */ 065@Singleton 066@Named 067public class DefaultInstaller 068 implements Installer, Service 069{ 070 071 private static final Logger LOGGER = LoggerFactory.getLogger( DefaultInstaller.class ); 072 073 private FileProcessor fileProcessor; 074 075 private RepositoryEventDispatcher repositoryEventDispatcher; 076 077 private Collection<MetadataGeneratorFactory> metadataFactories = new ArrayList<>(); 078 079 private SyncContextFactory syncContextFactory; 080 081 public DefaultInstaller() 082 { 083 // enables default constructor 084 } 085 086 @Inject 087 DefaultInstaller( FileProcessor fileProcessor, RepositoryEventDispatcher repositoryEventDispatcher, 088 Set<MetadataGeneratorFactory> metadataFactories, SyncContextFactory syncContextFactory ) 089 { 090 setFileProcessor( fileProcessor ); 091 setRepositoryEventDispatcher( repositoryEventDispatcher ); 092 setMetadataGeneratorFactories( metadataFactories ); 093 setSyncContextFactory( syncContextFactory ); 094 } 095 096 public void initService( ServiceLocator locator ) 097 { 098 setFileProcessor( locator.getService( FileProcessor.class ) ); 099 setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) ); 100 setMetadataGeneratorFactories( locator.getServices( MetadataGeneratorFactory.class ) ); 101 setSyncContextFactory( locator.getService( SyncContextFactory.class ) ); 102 } 103 104 public DefaultInstaller setFileProcessor( FileProcessor fileProcessor ) 105 { 106 this.fileProcessor = requireNonNull( fileProcessor, "file processor cannot be null" ); 107 return this; 108 } 109 110 public DefaultInstaller setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher ) 111 { 112 this.repositoryEventDispatcher = requireNonNull( repositoryEventDispatcher, 113 "repository event dispatcher cannot be null" ); 114 return this; 115 } 116 117 public DefaultInstaller addMetadataGeneratorFactory( MetadataGeneratorFactory factory ) 118 { 119 metadataFactories.add( requireNonNull( factory, "metadata generator factory cannot be null" ) ); 120 return this; 121 } 122 123 public DefaultInstaller setMetadataGeneratorFactories( Collection<MetadataGeneratorFactory> metadataFactories ) 124 { 125 if ( metadataFactories == null ) 126 { 127 this.metadataFactories = new ArrayList<>(); 128 } 129 else 130 { 131 this.metadataFactories = metadataFactories; 132 } 133 return this; 134 } 135 136 public DefaultInstaller setSyncContextFactory( SyncContextFactory syncContextFactory ) 137 { 138 this.syncContextFactory = requireNonNull( syncContextFactory, "sync context factory cannot be null" ); 139 return this; 140 } 141 142 public InstallResult install( RepositorySystemSession session, InstallRequest request ) 143 throws InstallationException 144 { 145 146 try ( SyncContext syncContext = syncContextFactory.newInstance( session, false ) ) 147 { 148 return install( syncContext, session, request ); 149 } 150 } 151 152 private InstallResult install( SyncContext syncContext, RepositorySystemSession session, InstallRequest request ) 153 throws InstallationException 154 { 155 InstallResult result = new InstallResult( request ); 156 157 RequestTrace trace = RequestTrace.newChild( request.getTrace(), request ); 158 159 List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request ); 160 161 List<Artifact> artifacts = new ArrayList<>( request.getArtifacts() ); 162 163 IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>(); 164 165 List<Metadata> metadatas = Utils.prepareMetadata( generators, artifacts ); 166 167 syncContext.acquire( artifacts, Utils.combine( request.getMetadata(), metadatas ) ); 168 169 for ( Metadata metadata : metadatas ) 170 { 171 install( session, trace, metadata ); 172 processedMetadata.put( metadata, null ); 173 result.addMetadata( metadata ); 174 } 175 176 for ( ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) 177 { 178 Artifact artifact = iterator.next(); 179 180 for ( MetadataGenerator generator : generators ) 181 { 182 artifact = generator.transformArtifact( artifact ); 183 } 184 185 iterator.set( artifact ); 186 187 install( session, trace, artifact ); 188 result.addArtifact( artifact ); 189 } 190 191 metadatas = Utils.finishMetadata( generators, artifacts ); 192 193 syncContext.acquire( null, metadatas ); 194 195 for ( Metadata metadata : metadatas ) 196 { 197 install( session, trace, metadata ); 198 processedMetadata.put( metadata, null ); 199 result.addMetadata( metadata ); 200 } 201 202 for ( Metadata metadata : request.getMetadata() ) 203 { 204 if ( !processedMetadata.containsKey( metadata ) ) 205 { 206 install( session, trace, metadata ); 207 result.addMetadata( metadata ); 208 } 209 } 210 211 return result; 212 } 213 214 private List<? extends MetadataGenerator> getMetadataGenerators( RepositorySystemSession session, 215 InstallRequest request ) 216 { 217 PrioritizedComponents<MetadataGeneratorFactory> factories = 218 Utils.sortMetadataGeneratorFactories( session, this.metadataFactories ); 219 220 List<MetadataGenerator> generators = new ArrayList<>(); 221 222 for ( PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled() ) 223 { 224 MetadataGenerator generator = factory.getComponent().newInstance( session, request ); 225 if ( generator != null ) 226 { 227 generators.add( generator ); 228 } 229 } 230 231 return generators; 232 } 233 234 private void install( RepositorySystemSession session, RequestTrace trace, Artifact artifact ) 235 throws InstallationException 236 { 237 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 238 239 File srcFile = artifact.getFile(); 240 241 Collection<FileTransformer> fileTransformers = session.getFileTransformerManager() 242 .getTransformersForArtifact( artifact ); 243 if ( fileTransformers.isEmpty() ) 244 { 245 install( session, trace, artifact, lrm, srcFile, null ); 246 } 247 else 248 { 249 for ( FileTransformer fileTransformer : fileTransformers ) 250 { 251 install( session, trace, artifact, lrm, srcFile, fileTransformer ); 252 } 253 } 254 } 255 256 private void install( RepositorySystemSession session, RequestTrace trace, Artifact artifact, 257 LocalRepositoryManager lrm, File srcFile, FileTransformer fileTransformer ) 258 throws InstallationException 259 { 260 final Artifact targetArtifact; 261 if ( fileTransformer != null ) 262 { 263 targetArtifact = fileTransformer.transformArtifact( artifact ); 264 } 265 else 266 { 267 targetArtifact = artifact; 268 } 269 270 File dstFile = new File( lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact( targetArtifact ) ); 271 272 artifactInstalling( session, trace, targetArtifact, dstFile ); 273 274 Exception exception = null; 275 try 276 { 277 if ( dstFile.equals( srcFile ) ) 278 { 279 throw new IllegalStateException( "cannot install " + dstFile + " to same path" ); 280 } 281 282 boolean copy = 283 "pom".equals( targetArtifact.getExtension() ) || srcFile.lastModified() != dstFile.lastModified() 284 || srcFile.length() != dstFile.length() || !srcFile.exists(); 285 286 if ( !copy ) 287 { 288 LOGGER.debug( "Skipped re-installing {} to {}, seems unchanged", srcFile, dstFile ); 289 } 290 else if ( fileTransformer != null ) 291 { 292 try ( InputStream is = fileTransformer.transformData( srcFile ) ) 293 { 294 fileProcessor.write( dstFile, is ); 295 dstFile.setLastModified( srcFile.lastModified() ); 296 } 297 } 298 else 299 { 300 fileProcessor.copy( srcFile, dstFile ); 301 dstFile.setLastModified( srcFile.lastModified() ); 302 } 303 304 lrm.add( session, new LocalArtifactRegistration( targetArtifact ) ); 305 } 306 catch ( Exception e ) 307 { 308 exception = e; 309 throw new InstallationException( "Failed to install artifact " + targetArtifact + ": " + e.getMessage(), 310 e ); 311 } 312 finally 313 { 314 artifactInstalled( session, trace, targetArtifact, dstFile, exception ); 315 } 316 } 317 318 private void install( RepositorySystemSession session, RequestTrace trace, Metadata metadata ) 319 throws InstallationException 320 { 321 LocalRepositoryManager lrm = session.getLocalRepositoryManager(); 322 323 File dstFile = new File( lrm.getRepository().getBasedir(), lrm.getPathForLocalMetadata( metadata ) ); 324 325 metadataInstalling( session, trace, metadata, dstFile ); 326 327 Exception exception = null; 328 try 329 { 330 if ( metadata instanceof MergeableMetadata ) 331 { 332 ( (MergeableMetadata) metadata ).merge( dstFile, dstFile ); 333 } 334 else 335 { 336 if ( dstFile.equals( metadata.getFile() ) ) 337 { 338 throw new IllegalStateException( "cannot install " + dstFile + " to same path" ); 339 } 340 fileProcessor.copy( metadata.getFile(), dstFile ); 341 } 342 343 lrm.add( session, new LocalMetadataRegistration( metadata ) ); 344 } 345 catch ( Exception e ) 346 { 347 exception = e; 348 throw new InstallationException( "Failed to install metadata " + metadata + ": " + e.getMessage(), e ); 349 } 350 finally 351 { 352 metadataInstalled( session, trace, metadata, dstFile, exception ); 353 } 354 } 355 356 private void artifactInstalling( RepositorySystemSession session, RequestTrace trace, Artifact artifact, 357 File dstFile ) 358 { 359 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_INSTALLING ); 360 event.setTrace( trace ); 361 event.setArtifact( artifact ); 362 event.setRepository( session.getLocalRepositoryManager().getRepository() ); 363 event.setFile( dstFile ); 364 365 repositoryEventDispatcher.dispatch( event.build() ); 366 } 367 368 private void artifactInstalled( RepositorySystemSession session, RequestTrace trace, Artifact artifact, 369 File dstFile, Exception exception ) 370 { 371 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_INSTALLED ); 372 event.setTrace( trace ); 373 event.setArtifact( artifact ); 374 event.setRepository( session.getLocalRepositoryManager().getRepository() ); 375 event.setFile( dstFile ); 376 event.setException( exception ); 377 378 repositoryEventDispatcher.dispatch( event.build() ); 379 } 380 381 private void metadataInstalling( RepositorySystemSession session, RequestTrace trace, Metadata metadata, 382 File dstFile ) 383 { 384 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INSTALLING ); 385 event.setTrace( trace ); 386 event.setMetadata( metadata ); 387 event.setRepository( session.getLocalRepositoryManager().getRepository() ); 388 event.setFile( dstFile ); 389 390 repositoryEventDispatcher.dispatch( event.build() ); 391 } 392 393 private void metadataInstalled( RepositorySystemSession session, RequestTrace trace, Metadata metadata, 394 File dstFile, Exception exception ) 395 { 396 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INSTALLED ); 397 event.setTrace( trace ); 398 event.setMetadata( metadata ); 399 event.setRepository( session.getLocalRepositoryManager().getRepository() ); 400 event.setFile( dstFile ); 401 event.setException( exception ); 402 403 repositoryEventDispatcher.dispatch( event.build() ); 404 } 405 406}