View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.util.*;
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.IdentityHashMap;
31  import java.util.List;
32  import java.util.ListIterator;
33  import java.util.Map;
34  
35  import org.eclipse.aether.RepositoryEvent;
36  import org.eclipse.aether.RepositoryEvent.EventType;
37  import org.eclipse.aether.RepositorySystemSession;
38  import org.eclipse.aether.RequestTrace;
39  import org.eclipse.aether.SyncContext;
40  import org.eclipse.aether.artifact.Artifact;
41  import org.eclipse.aether.impl.Installer;
42  import org.eclipse.aether.impl.MetadataGenerator;
43  import org.eclipse.aether.impl.MetadataGeneratorFactory;
44  import org.eclipse.aether.impl.RepositoryEventDispatcher;
45  import org.eclipse.aether.installation.InstallRequest;
46  import org.eclipse.aether.installation.InstallResult;
47  import org.eclipse.aether.installation.InstallationException;
48  import org.eclipse.aether.metadata.MergeableMetadata;
49  import org.eclipse.aether.metadata.Metadata;
50  import org.eclipse.aether.repository.LocalArtifactRegistration;
51  import org.eclipse.aether.repository.LocalMetadataRegistration;
52  import org.eclipse.aether.repository.LocalRepositoryManager;
53  import org.eclipse.aether.spi.artifact.generator.ArtifactGenerator;
54  import org.eclipse.aether.spi.artifact.generator.ArtifactGeneratorFactory;
55  import org.eclipse.aether.spi.io.PathProcessor;
56  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
57  import org.slf4j.Logger;
58  import org.slf4j.LoggerFactory;
59  
60  import static java.util.Objects.requireNonNull;
61  
62  /**
63   */
64  @Singleton
65  @Named
66  public class DefaultInstaller implements Installer {
67      private final Logger logger = LoggerFactory.getLogger(getClass());
68  
69      private final PathProcessor pathProcessor;
70  
71      private final RepositoryEventDispatcher repositoryEventDispatcher;
72  
73      private final Map<String, ArtifactGeneratorFactory> artifactFactories;
74  
75      private final Map<String, MetadataGeneratorFactory> metadataFactories;
76  
77      private final SyncContextFactory syncContextFactory;
78  
79      @Inject
80      public DefaultInstaller(
81              PathProcessor pathProcessor,
82              RepositoryEventDispatcher repositoryEventDispatcher,
83              Map<String, ArtifactGeneratorFactory> artifactFactories,
84              Map<String, MetadataGeneratorFactory> metadataFactories,
85              SyncContextFactory syncContextFactory) {
86          this.pathProcessor = requireNonNull(pathProcessor, "path processor cannot be null");
87          this.repositoryEventDispatcher =
88                  requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null");
89          this.artifactFactories = Collections.unmodifiableMap(artifactFactories);
90          this.metadataFactories = Collections.unmodifiableMap(metadataFactories);
91          this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
92      }
93  
94      @Override
95      public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException {
96          requireNonNull(session, "session cannot be null");
97          requireNonNull(request, "request cannot be null");
98          try (SyncContext syncContext = syncContextFactory.newInstance(session, false)) {
99              return install(syncContext, session, request);
100         }
101     }
102 
103     private InstallResult install(SyncContext syncContext, RepositorySystemSession session, InstallRequest request)
104             throws InstallationException {
105         InstallResult result = new InstallResult(request);
106 
107         RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
108 
109         List<Artifact> artifacts = new ArrayList<>(request.getArtifacts());
110         List<? extends ArtifactGenerator> artifactGenerators = getArtifactGenerators(session, request);
111         try {
112             List<Artifact> generatedArtifacts = new ArrayList<>();
113             for (ArtifactGenerator artifactGenerator : artifactGenerators) {
114                 Collection<? extends Artifact> generated = artifactGenerator.generate(generatedArtifacts);
115                 for (Artifact generatedArtifact : generated) {
116                     Map<String, String> properties = new HashMap<>(generatedArtifact.getProperties());
117                     properties.put(
118                             ArtifactGeneratorFactory.ARTIFACT_GENERATOR_ID,
119                             requireNonNull(artifactGenerator.generatorId(), "generatorId"));
120                     Artifact ga = generatedArtifact.setProperties(properties);
121                     generatedArtifacts.add(ga);
122                 }
123             }
124             artifacts.addAll(generatedArtifacts);
125 
126             List<? extends MetadataGenerator> metadataGenerators = getMetadataGenerators(session, request);
127 
128             IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
129 
130             List<Metadata> metadatas = Utils.prepareMetadata(metadataGenerators, artifacts);
131 
132             syncContext.acquire(artifacts, Utils.combine(request.getMetadata(), metadatas));
133 
134             for (Metadata metadata : metadatas) {
135                 install(session, trace, metadata);
136                 processedMetadata.put(metadata, null);
137                 result.addMetadata(metadata);
138             }
139 
140             for (ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) {
141                 Artifact artifact = iterator.next();
142 
143                 for (MetadataGenerator generator : metadataGenerators) {
144                     artifact = generator.transformArtifact(artifact);
145                 }
146 
147                 iterator.set(artifact);
148 
149                 install(session, trace, artifact);
150                 if (artifact.getProperty(ArtifactGeneratorFactory.ARTIFACT_GENERATOR_ID, null) == null) {
151                     result.addArtifact(artifact);
152                 }
153             }
154 
155             metadatas = Utils.finishMetadata(metadataGenerators, artifacts);
156 
157             syncContext.acquire(null, metadatas);
158 
159             for (Metadata metadata : metadatas) {
160                 install(session, trace, metadata);
161                 processedMetadata.put(metadata, null);
162                 result.addMetadata(metadata);
163             }
164 
165             for (Metadata metadata : request.getMetadata()) {
166                 if (!processedMetadata.containsKey(metadata)) {
167                     install(session, trace, metadata);
168                     result.addMetadata(metadata);
169                 }
170             }
171 
172             return result;
173         } finally {
174             for (ArtifactGenerator artifactGenerator : artifactGenerators) {
175                 try {
176                     artifactGenerator.close();
177                 } catch (Exception e) {
178                     logger.warn("ArtifactGenerator close failure: {}", artifactGenerator.generatorId(), e);
179                 }
180             }
181         }
182     }
183 
184     private List<? extends ArtifactGenerator> getArtifactGenerators(
185             RepositorySystemSession session, InstallRequest request) {
186         PrioritizedComponents<ArtifactGeneratorFactory> factories =
187                 Utils.sortArtifactGeneratorFactories(session, artifactFactories);
188 
189         List<ArtifactGenerator> generators = new ArrayList<>();
190 
191         for (PrioritizedComponent<ArtifactGeneratorFactory> factory : factories.getEnabled()) {
192             ArtifactGenerator generator = factory.getComponent().newInstance(session, request);
193             if (generator != null) {
194                 generators.add(generator);
195             }
196         }
197 
198         return generators;
199     }
200 
201     private List<? extends MetadataGenerator> getMetadataGenerators(
202             RepositorySystemSession session, InstallRequest request) {
203         PrioritizedComponents<MetadataGeneratorFactory> factories =
204                 Utils.sortMetadataGeneratorFactories(session, metadataFactories);
205 
206         List<MetadataGenerator> generators = new ArrayList<>();
207 
208         for (PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled()) {
209             MetadataGenerator generator = factory.getComponent().newInstance(session, request);
210             if (generator != null) {
211                 generators.add(generator);
212             }
213         }
214 
215         return generators;
216     }
217 
218     private void install(RepositorySystemSession session, RequestTrace trace, Artifact artifact)
219             throws InstallationException {
220         final LocalRepositoryManager lrm = session.getLocalRepositoryManager();
221         final Path srcPath = artifact.getPath();
222         final Path dstPath = lrm.getRepository().getBasePath().resolve(lrm.getPathForLocalArtifact(artifact));
223 
224         artifactInstalling(session, trace, artifact, dstPath);
225 
226         Exception exception = null;
227         try {
228             if (dstPath.equals(srcPath)) {
229                 throw new IllegalStateException("cannot install " + dstPath + " to same path");
230             }
231 
232             pathProcessor.copy(srcPath, dstPath);
233             Files.setLastModifiedTime(dstPath, Files.getLastModifiedTime(srcPath));
234             lrm.add(session, new LocalArtifactRegistration(artifact));
235         } catch (Exception e) {
236             exception = e;
237             throw new InstallationException("Failed to install artifact " + artifact + ": " + e.getMessage(), e);
238         } finally {
239             artifactInstalled(session, trace, artifact, dstPath, exception);
240         }
241     }
242 
243     private void install(RepositorySystemSession session, RequestTrace trace, Metadata metadata)
244             throws InstallationException {
245         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
246 
247         Path dstPath = lrm.getRepository().getBasePath().resolve(lrm.getPathForLocalMetadata(metadata));
248 
249         metadataInstalling(session, trace, metadata, dstPath);
250 
251         Exception exception = null;
252         try {
253             if (metadata instanceof MergeableMetadata) {
254                 ((MergeableMetadata) metadata).merge(dstPath, dstPath);
255             } else {
256                 if (dstPath.equals(metadata.getPath())) {
257                     throw new IllegalStateException("cannot install " + dstPath + " to same path");
258                 }
259                 pathProcessor.copy(metadata.getPath(), dstPath);
260             }
261 
262             lrm.add(session, new LocalMetadataRegistration(metadata));
263         } catch (Exception e) {
264             exception = e;
265             throw new InstallationException("Failed to install metadata " + metadata + ": " + e.getMessage(), e);
266         } finally {
267             metadataInstalled(session, trace, metadata, dstPath, exception);
268         }
269     }
270 
271     private void artifactInstalling(
272             RepositorySystemSession session, RequestTrace trace, Artifact artifact, Path dstPath) {
273         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLING);
274         event.setTrace(trace);
275         event.setArtifact(artifact);
276         event.setRepository(session.getLocalRepositoryManager().getRepository());
277         event.setPath(dstPath);
278 
279         repositoryEventDispatcher.dispatch(event.build());
280     }
281 
282     private void artifactInstalled(
283             RepositorySystemSession session, RequestTrace trace, Artifact artifact, Path dstPath, Exception exception) {
284         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLED);
285         event.setTrace(trace);
286         event.setArtifact(artifact);
287         event.setRepository(session.getLocalRepositoryManager().getRepository());
288         event.setPath(dstPath);
289         event.setException(exception);
290 
291         repositoryEventDispatcher.dispatch(event.build());
292     }
293 
294     private void metadataInstalling(
295             RepositorySystemSession session, RequestTrace trace, Metadata metadata, Path dstPath) {
296         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLING);
297         event.setTrace(trace);
298         event.setMetadata(metadata);
299         event.setRepository(session.getLocalRepositoryManager().getRepository());
300         event.setPath(dstPath);
301 
302         repositoryEventDispatcher.dispatch(event.build());
303     }
304 
305     private void metadataInstalled(
306             RepositorySystemSession session, RequestTrace trace, Metadata metadata, Path dstPath, Exception exception) {
307         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLED);
308         event.setTrace(trace);
309         event.setMetadata(metadata);
310         event.setRepository(session.getLocalRepositoryManager().getRepository());
311         event.setPath(dstPath);
312         event.setException(exception);
313 
314         repositoryEventDispatcher.dispatch(event.build());
315     }
316 }