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