001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.internal.impl;
020
021import javax.inject.Inject;
022import javax.inject.Named;
023import javax.inject.Singleton;
024
025import java.io.File;
026import java.util.ArrayList;
027import java.util.Collections;
028import java.util.IdentityHashMap;
029import java.util.List;
030import java.util.ListIterator;
031import java.util.Map;
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.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.synccontext.SyncContextFactory;
053
054import static java.util.Objects.requireNonNull;
055
056/**
057 */
058@Singleton
059@Named
060public class DefaultInstaller implements Installer {
061    private final FileProcessor fileProcessor;
062
063    private final RepositoryEventDispatcher repositoryEventDispatcher;
064
065    private final Map<String, MetadataGeneratorFactory> metadataFactories;
066
067    private final SyncContextFactory syncContextFactory;
068
069    @Inject
070    public DefaultInstaller(
071            FileProcessor fileProcessor,
072            RepositoryEventDispatcher repositoryEventDispatcher,
073            Map<String, MetadataGeneratorFactory> metadataFactories,
074            SyncContextFactory syncContextFactory) {
075        this.fileProcessor = requireNonNull(fileProcessor, "file processor cannot be null");
076        this.repositoryEventDispatcher =
077                requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null");
078        this.metadataFactories = Collections.unmodifiableMap(metadataFactories);
079        this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
080    }
081
082    @Override
083    public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException {
084        requireNonNull(session, "session cannot be null");
085        requireNonNull(request, "request cannot be null");
086        try (SyncContext syncContext = syncContextFactory.newInstance(session, false)) {
087            return install(syncContext, session, request);
088        }
089    }
090
091    private InstallResult install(SyncContext syncContext, RepositorySystemSession session, InstallRequest request)
092            throws InstallationException {
093        InstallResult result = new InstallResult(request);
094
095        RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
096
097        List<? extends MetadataGenerator> generators = getMetadataGenerators(session, request);
098
099        List<Artifact> artifacts = new ArrayList<>(request.getArtifacts());
100
101        IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
102
103        List<Metadata> metadatas = Utils.prepareMetadata(generators, artifacts);
104
105        syncContext.acquire(artifacts, Utils.combine(request.getMetadata(), metadatas));
106
107        for (Metadata metadata : metadatas) {
108            install(session, trace, metadata);
109            processedMetadata.put(metadata, null);
110            result.addMetadata(metadata);
111        }
112
113        for (ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) {
114            Artifact artifact = iterator.next();
115
116            for (MetadataGenerator generator : generators) {
117                artifact = generator.transformArtifact(artifact);
118            }
119
120            iterator.set(artifact);
121
122            install(session, trace, artifact);
123            result.addArtifact(artifact);
124        }
125
126        metadatas = Utils.finishMetadata(generators, artifacts);
127
128        syncContext.acquire(null, metadatas);
129
130        for (Metadata metadata : metadatas) {
131            install(session, trace, metadata);
132            processedMetadata.put(metadata, null);
133            result.addMetadata(metadata);
134        }
135
136        for (Metadata metadata : request.getMetadata()) {
137            if (!processedMetadata.containsKey(metadata)) {
138                install(session, trace, metadata);
139                result.addMetadata(metadata);
140            }
141        }
142
143        return result;
144    }
145
146    private List<? extends MetadataGenerator> getMetadataGenerators(
147            RepositorySystemSession session, InstallRequest request) {
148        PrioritizedComponents<MetadataGeneratorFactory> factories =
149                Utils.sortMetadataGeneratorFactories(session, metadataFactories);
150
151        List<MetadataGenerator> generators = new ArrayList<>();
152
153        for (PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled()) {
154            MetadataGenerator generator = factory.getComponent().newInstance(session, request);
155            if (generator != null) {
156                generators.add(generator);
157            }
158        }
159
160        return generators;
161    }
162
163    private void install(RepositorySystemSession session, RequestTrace trace, Artifact artifact)
164            throws InstallationException {
165        final LocalRepositoryManager lrm = session.getLocalRepositoryManager();
166        final File srcFile = artifact.getFile();
167        final File dstFile = new File(lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact(artifact));
168
169        artifactInstalling(session, trace, artifact, dstFile);
170
171        Exception exception = null;
172        try {
173            if (dstFile.equals(srcFile)) {
174                throw new IllegalStateException("cannot install " + dstFile + " to same path");
175            }
176
177            fileProcessor.copy(srcFile, dstFile);
178            dstFile.setLastModified(srcFile.lastModified());
179            lrm.add(session, new LocalArtifactRegistration(artifact));
180        } catch (Exception e) {
181            exception = e;
182            throw new InstallationException("Failed to install artifact " + artifact + ": " + e.getMessage(), e);
183        } finally {
184            artifactInstalled(session, trace, artifact, dstFile, exception);
185        }
186    }
187
188    private void install(RepositorySystemSession session, RequestTrace trace, Metadata metadata)
189            throws InstallationException {
190        LocalRepositoryManager lrm = session.getLocalRepositoryManager();
191
192        File dstFile = new File(lrm.getRepository().getBasedir(), lrm.getPathForLocalMetadata(metadata));
193
194        metadataInstalling(session, trace, metadata, dstFile);
195
196        Exception exception = null;
197        try {
198            if (metadata instanceof MergeableMetadata) {
199                ((MergeableMetadata) metadata).merge(dstFile, dstFile);
200            } else {
201                if (dstFile.equals(metadata.getFile())) {
202                    throw new IllegalStateException("cannot install " + dstFile + " to same path");
203                }
204                fileProcessor.copy(metadata.getFile(), dstFile);
205            }
206
207            lrm.add(session, new LocalMetadataRegistration(metadata));
208        } catch (Exception e) {
209            exception = e;
210            throw new InstallationException("Failed to install metadata " + metadata + ": " + e.getMessage(), e);
211        } finally {
212            metadataInstalled(session, trace, metadata, dstFile, exception);
213        }
214    }
215
216    private void artifactInstalling(
217            RepositorySystemSession session, RequestTrace trace, Artifact artifact, File dstFile) {
218        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLING);
219        event.setTrace(trace);
220        event.setArtifact(artifact);
221        event.setRepository(session.getLocalRepositoryManager().getRepository());
222        event.setFile(dstFile);
223
224        repositoryEventDispatcher.dispatch(event.build());
225    }
226
227    private void artifactInstalled(
228            RepositorySystemSession session, RequestTrace trace, Artifact artifact, File dstFile, Exception exception) {
229        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLED);
230        event.setTrace(trace);
231        event.setArtifact(artifact);
232        event.setRepository(session.getLocalRepositoryManager().getRepository());
233        event.setFile(dstFile);
234        event.setException(exception);
235
236        repositoryEventDispatcher.dispatch(event.build());
237    }
238
239    private void metadataInstalling(
240            RepositorySystemSession session, RequestTrace trace, Metadata metadata, File dstFile) {
241        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLING);
242        event.setTrace(trace);
243        event.setMetadata(metadata);
244        event.setRepository(session.getLocalRepositoryManager().getRepository());
245        event.setFile(dstFile);
246
247        repositoryEventDispatcher.dispatch(event.build());
248    }
249
250    private void metadataInstalled(
251            RepositorySystemSession session, RequestTrace trace, Metadata metadata, File dstFile, Exception exception) {
252        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLED);
253        event.setTrace(trace);
254        event.setMetadata(metadata);
255        event.setRepository(session.getLocalRepositoryManager().getRepository());
256        event.setFile(dstFile);
257        event.setException(exception);
258
259        repositoryEventDispatcher.dispatch(event.build());
260    }
261}