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