View Javadoc
1   package org.eclipse.aether.internal.impl;
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 static java.util.Objects.requireNonNull;
23  
24  import java.io.File;
25  import java.io.InputStream;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.IdentityHashMap;
29  import java.util.List;
30  import java.util.ListIterator;
31  import java.util.Set;
32  
33  import javax.inject.Inject;
34  import javax.inject.Named;
35  import javax.inject.Singleton;
36  
37  import org.eclipse.aether.RepositoryEvent;
38  import org.eclipse.aether.RepositoryEvent.EventType;
39  import org.eclipse.aether.RepositorySystemSession;
40  import org.eclipse.aether.RequestTrace;
41  import org.eclipse.aether.SyncContext;
42  import org.eclipse.aether.artifact.Artifact;
43  import org.eclipse.aether.impl.Installer;
44  import org.eclipse.aether.impl.MetadataGenerator;
45  import org.eclipse.aether.impl.MetadataGeneratorFactory;
46  import org.eclipse.aether.impl.RepositoryEventDispatcher;
47  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
48  import org.eclipse.aether.installation.InstallRequest;
49  import org.eclipse.aether.installation.InstallResult;
50  import org.eclipse.aether.installation.InstallationException;
51  import org.eclipse.aether.metadata.MergeableMetadata;
52  import org.eclipse.aether.metadata.Metadata;
53  import org.eclipse.aether.repository.LocalArtifactRegistration;
54  import org.eclipse.aether.repository.LocalMetadataRegistration;
55  import org.eclipse.aether.repository.LocalRepositoryManager;
56  import org.eclipse.aether.spi.io.FileProcessor;
57  import org.eclipse.aether.spi.locator.Service;
58  import org.eclipse.aether.spi.locator.ServiceLocator;
59  import org.eclipse.aether.transform.FileTransformer;
60  import org.slf4j.Logger;
61  import org.slf4j.LoggerFactory;
62  
63  /**
64   */
65  @Singleton
66  @Named
67  public class DefaultInstaller
68      implements Installer, Service
69  {
70  
71      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultInstaller.class );
72  
73      private FileProcessor fileProcessor;
74  
75      private RepositoryEventDispatcher repositoryEventDispatcher;
76  
77      private Collection<MetadataGeneratorFactory> metadataFactories = new ArrayList<>();
78  
79      private SyncContextFactory syncContextFactory;
80  
81      public DefaultInstaller()
82      {
83          // enables default constructor
84      }
85  
86      @Inject
87      DefaultInstaller( FileProcessor fileProcessor, RepositoryEventDispatcher repositoryEventDispatcher,
88                        Set<MetadataGeneratorFactory> metadataFactories, SyncContextFactory syncContextFactory )
89      {
90          setFileProcessor( fileProcessor );
91          setRepositoryEventDispatcher( repositoryEventDispatcher );
92          setMetadataGeneratorFactories( metadataFactories );
93          setSyncContextFactory( syncContextFactory );
94      }
95  
96      public void initService( ServiceLocator locator )
97      {
98          setFileProcessor( locator.getService( FileProcessor.class ) );
99          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 }