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.Path;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashMap;
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.artifact.transformer.ArtifactTransformer;
56  import org.eclipse.aether.spi.io.PathProcessor;
57  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
58  import org.slf4j.Logger;
59  import org.slf4j.LoggerFactory;
60  
61  import static java.util.Objects.requireNonNull;
62  
63  /**
64   */
65  @Singleton
66  @Named
67  public class DefaultInstaller implements Installer {
68      private final Logger logger = LoggerFactory.getLogger(getClass());
69  
70      private final PathProcessor pathProcessor;
71  
72      private final RepositoryEventDispatcher repositoryEventDispatcher;
73  
74      private final Map<String, ArtifactGeneratorFactory> artifactFactories;
75  
76      private final Map<String, MetadataGeneratorFactory> metadataFactories;
77  
78      private final Map<String, ArtifactTransformer> artifactTransformers;
79  
80      private final SyncContextFactory syncContextFactory;
81  
82      @Inject
83      public DefaultInstaller(
84              PathProcessor pathProcessor,
85              RepositoryEventDispatcher repositoryEventDispatcher,
86              Map<String, ArtifactGeneratorFactory> artifactFactories,
87              Map<String, MetadataGeneratorFactory> metadataFactories,
88              Map<String, ArtifactTransformer> artifactTransformers,
89              SyncContextFactory syncContextFactory) {
90          this.pathProcessor = requireNonNull(pathProcessor, "path processor cannot be null");
91          this.repositoryEventDispatcher =
92                  requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null");
93          this.artifactFactories = Collections.unmodifiableMap(artifactFactories);
94          this.metadataFactories = Collections.unmodifiableMap(metadataFactories);
95          this.artifactTransformers = Collections.unmodifiableMap(artifactTransformers);
96          this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
97      }
98  
99      @Override
100     public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException {
101         requireNonNull(session, "session cannot be null");
102         requireNonNull(request, "request cannot be null");
103         for (ArtifactTransformer transformer : artifactTransformers.values()) {
104             request = transformer.transformInstallArtifacts(session, request);
105         }
106         try (SyncContext syncContext = syncContextFactory.newInstance(session, false)) {
107             return install(syncContext, session, request);
108         }
109     }
110 
111     private InstallResult install(SyncContext syncContext, RepositorySystemSession session, InstallRequest request)
112             throws InstallationException {
113         InstallResult result = new InstallResult(request);
114 
115         RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
116 
117         List<Artifact> artifacts = new ArrayList<>(request.getArtifacts());
118         List<? extends ArtifactGenerator> artifactGenerators =
119                 Utils.getArtifactGenerators(session, artifactFactories, request);
120         try {
121             List<Artifact> generatedArtifacts = new ArrayList<>();
122             for (ArtifactGenerator artifactGenerator : artifactGenerators) {
123                 Collection<? extends Artifact> generated = artifactGenerator.generate(generatedArtifacts);
124                 for (Artifact generatedArtifact : generated) {
125                     Map<String, String> properties = new HashMap<>(generatedArtifact.getProperties());
126                     properties.put(
127                             ArtifactGeneratorFactory.ARTIFACT_GENERATOR_ID,
128                             requireNonNull(artifactGenerator.generatorId(), "generatorId"));
129                     Artifact ga = generatedArtifact.setProperties(properties);
130                     generatedArtifacts.add(ga);
131                 }
132             }
133             artifacts.addAll(generatedArtifacts);
134 
135             List<? extends MetadataGenerator> metadataGenerators =
136                     Utils.getMetadataGenerators(session, metadataFactories, request);
137 
138             IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
139 
140             List<Metadata> metadatas = Utils.prepareMetadata(metadataGenerators, artifacts);
141 
142             syncContext.acquire(artifacts, Utils.combine(request.getMetadata(), metadatas));
143 
144             for (Metadata metadata : metadatas) {
145                 install(session, trace, metadata);
146                 processedMetadata.put(metadata, null);
147                 result.addMetadata(metadata);
148             }
149 
150             for (ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) {
151                 Artifact artifact = iterator.next();
152 
153                 for (MetadataGenerator generator : metadataGenerators) {
154                     artifact = generator.transformArtifact(artifact);
155                 }
156 
157                 iterator.set(artifact);
158 
159                 install(session, trace, artifact);
160                 if (artifact.getProperty(ArtifactGeneratorFactory.ARTIFACT_GENERATOR_ID, null) == null) {
161                     result.addArtifact(artifact);
162                 }
163             }
164 
165             metadatas = Utils.finishMetadata(metadataGenerators, artifacts);
166 
167             syncContext.acquire(null, metadatas);
168 
169             for (Metadata metadata : metadatas) {
170                 install(session, trace, metadata);
171                 processedMetadata.put(metadata, null);
172                 result.addMetadata(metadata);
173             }
174 
175             for (Metadata metadata : request.getMetadata()) {
176                 if (!processedMetadata.containsKey(metadata)) {
177                     install(session, trace, metadata);
178                     result.addMetadata(metadata);
179                 }
180             }
181 
182             return result;
183         } finally {
184             for (ArtifactGenerator artifactGenerator : artifactGenerators) {
185                 try {
186                     artifactGenerator.close();
187                 } catch (Exception e) {
188                     logger.warn("ArtifactGenerator close failure: {}", artifactGenerator.generatorId(), e);
189                 }
190             }
191         }
192     }
193 
194     private void install(RepositorySystemSession session, RequestTrace trace, Artifact artifact)
195             throws InstallationException {
196         final LocalRepositoryManager lrm = session.getLocalRepositoryManager();
197         final Path srcPath = artifact.getPath();
198         final Path dstPath = lrm.getAbsolutePathForLocalArtifact(artifact);
199 
200         artifactInstalling(session, trace, artifact, dstPath);
201 
202         Exception exception = null;
203         try {
204             if (dstPath.equals(srcPath)) {
205                 throw new IllegalStateException("cannot install " + dstPath + " to same path");
206             }
207 
208             pathProcessor.copyWithTimestamp(srcPath, dstPath);
209             lrm.add(session, new LocalArtifactRegistration(artifact));
210         } catch (Exception e) {
211             exception = e;
212             throw new InstallationException("Failed to install artifact " + artifact + ": " + e.getMessage(), e);
213         } finally {
214             artifactInstalled(session, trace, artifact, dstPath, exception);
215         }
216     }
217 
218     private void install(RepositorySystemSession session, RequestTrace trace, Metadata metadata)
219             throws InstallationException {
220         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
221 
222         Path dstPath = lrm.getAbsolutePathForLocalMetadata(metadata);
223 
224         metadataInstalling(session, trace, metadata, dstPath);
225 
226         Exception exception = null;
227         try {
228             if (metadata instanceof MergeableMetadata) {
229                 ((MergeableMetadata) metadata).merge(dstPath, dstPath);
230             } else {
231                 if (dstPath.equals(metadata.getPath())) {
232                     throw new IllegalStateException("cannot install " + dstPath + " to same path");
233                 }
234                 pathProcessor.copy(metadata.getPath(), dstPath);
235             }
236 
237             lrm.add(session, new LocalMetadataRegistration(metadata));
238         } catch (Exception e) {
239             exception = e;
240             throw new InstallationException("Failed to install metadata " + metadata + ": " + e.getMessage(), e);
241         } finally {
242             metadataInstalled(session, trace, metadata, dstPath, exception);
243         }
244     }
245 
246     private void artifactInstalling(
247             RepositorySystemSession session, RequestTrace trace, Artifact artifact, Path dstPath) {
248         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLING);
249         event.setTrace(trace);
250         event.setArtifact(artifact);
251         event.setRepository(session.getLocalRepositoryManager().getRepository());
252         event.setPath(dstPath);
253 
254         repositoryEventDispatcher.dispatch(event.build());
255     }
256 
257     private void artifactInstalled(
258             RepositorySystemSession session, RequestTrace trace, Artifact artifact, Path dstPath, Exception exception) {
259         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLED);
260         event.setTrace(trace);
261         event.setArtifact(artifact);
262         event.setRepository(session.getLocalRepositoryManager().getRepository());
263         event.setPath(dstPath);
264         event.setException(exception);
265 
266         repositoryEventDispatcher.dispatch(event.build());
267     }
268 
269     private void metadataInstalling(
270             RepositorySystemSession session, RequestTrace trace, Metadata metadata, Path dstPath) {
271         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLING);
272         event.setTrace(trace);
273         event.setMetadata(metadata);
274         event.setRepository(session.getLocalRepositoryManager().getRepository());
275         event.setPath(dstPath);
276 
277         repositoryEventDispatcher.dispatch(event.build());
278     }
279 
280     private void metadataInstalled(
281             RepositorySystemSession session, RequestTrace trace, Metadata metadata, Path dstPath, Exception exception) {
282         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLED);
283         event.setTrace(trace);
284         event.setMetadata(metadata);
285         event.setRepository(session.getLocalRepositoryManager().getRepository());
286         event.setPath(dstPath);
287         event.setException(exception);
288 
289         repositoryEventDispatcher.dispatch(event.build());
290     }
291 }