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