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.io.File;
26  import java.io.InputStream;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.IdentityHashMap;
30  import java.util.List;
31  import java.util.ListIterator;
32  import java.util.Set;
33  
34  import org.eclipse.aether.RepositoryEvent;
35  import org.eclipse.aether.RepositoryEvent.EventType;
36  import org.eclipse.aether.RepositorySystemSession;
37  import org.eclipse.aether.RequestTrace;
38  import org.eclipse.aether.SyncContext;
39  import org.eclipse.aether.artifact.Artifact;
40  import org.eclipse.aether.impl.Installer;
41  import org.eclipse.aether.impl.MetadataGenerator;
42  import org.eclipse.aether.impl.MetadataGeneratorFactory;
43  import org.eclipse.aether.impl.RepositoryEventDispatcher;
44  import org.eclipse.aether.installation.InstallRequest;
45  import org.eclipse.aether.installation.InstallResult;
46  import org.eclipse.aether.installation.InstallationException;
47  import org.eclipse.aether.metadata.MergeableMetadata;
48  import org.eclipse.aether.metadata.Metadata;
49  import org.eclipse.aether.repository.LocalArtifactRegistration;
50  import org.eclipse.aether.repository.LocalMetadataRegistration;
51  import org.eclipse.aether.repository.LocalRepositoryManager;
52  import org.eclipse.aether.spi.io.FileProcessor;
53  import org.eclipse.aether.spi.locator.Service;
54  import org.eclipse.aether.spi.locator.ServiceLocator;
55  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
56  import org.eclipse.aether.transform.FileTransformer;
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, Service {
67  
68      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultInstaller.class);
69  
70      private FileProcessor fileProcessor;
71  
72      private RepositoryEventDispatcher repositoryEventDispatcher;
73  
74      private Collection<MetadataGeneratorFactory> metadataFactories = new ArrayList<>();
75  
76      private SyncContextFactory syncContextFactory;
77  
78      public DefaultInstaller() {
79          // enables default constructor
80      }
81  
82      @Inject
83      DefaultInstaller(
84              FileProcessor fileProcessor,
85              RepositoryEventDispatcher repositoryEventDispatcher,
86              Set<MetadataGeneratorFactory> metadataFactories,
87              SyncContextFactory syncContextFactory) {
88          setFileProcessor(fileProcessor);
89          setRepositoryEventDispatcher(repositoryEventDispatcher);
90          setMetadataGeneratorFactories(metadataFactories);
91          setSyncContextFactory(syncContextFactory);
92      }
93  
94      public void initService(ServiceLocator locator) {
95          setFileProcessor(locator.getService(FileProcessor.class));
96          setRepositoryEventDispatcher(locator.getService(RepositoryEventDispatcher.class));
97          setMetadataGeneratorFactories(locator.getServices(MetadataGeneratorFactory.class));
98          setSyncContextFactory(locator.getService(SyncContextFactory.class));
99      }
100 
101     public DefaultInstaller setFileProcessor(FileProcessor fileProcessor) {
102         this.fileProcessor = requireNonNull(fileProcessor, "file processor cannot be null");
103         return this;
104     }
105 
106     public DefaultInstaller setRepositoryEventDispatcher(RepositoryEventDispatcher repositoryEventDispatcher) {
107         this.repositoryEventDispatcher =
108                 requireNonNull(repositoryEventDispatcher, "repository event dispatcher cannot be null");
109         return this;
110     }
111 
112     public DefaultInstaller addMetadataGeneratorFactory(MetadataGeneratorFactory factory) {
113         metadataFactories.add(requireNonNull(factory, "metadata generator factory cannot be null"));
114         return this;
115     }
116 
117     public DefaultInstaller setMetadataGeneratorFactories(Collection<MetadataGeneratorFactory> metadataFactories) {
118         if (metadataFactories == null) {
119             this.metadataFactories = new ArrayList<>();
120         } else {
121             this.metadataFactories = metadataFactories;
122         }
123         return this;
124     }
125 
126     public DefaultInstaller setSyncContextFactory(SyncContextFactory syncContextFactory) {
127         this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
128         return this;
129     }
130 
131     public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException {
132         requireNonNull(session, "session cannot be null");
133         requireNonNull(request, "request cannot be null");
134         try (SyncContext syncContext = syncContextFactory.newInstance(session, false)) {
135             return install(syncContext, session, request);
136         }
137     }
138 
139     private InstallResult install(SyncContext syncContext, RepositorySystemSession session, InstallRequest request)
140             throws InstallationException {
141         InstallResult result = new InstallResult(request);
142 
143         RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
144 
145         List<? extends MetadataGenerator> generators = getMetadataGenerators(session, request);
146 
147         List<Artifact> artifacts = new ArrayList<>(request.getArtifacts());
148 
149         IdentityHashMap<Metadata, Object> processedMetadata = new IdentityHashMap<>();
150 
151         List<Metadata> metadatas = Utils.prepareMetadata(generators, artifacts);
152 
153         syncContext.acquire(artifacts, Utils.combine(request.getMetadata(), metadatas));
154 
155         for (Metadata metadata : metadatas) {
156             install(session, trace, metadata);
157             processedMetadata.put(metadata, null);
158             result.addMetadata(metadata);
159         }
160 
161         for (ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) {
162             Artifact artifact = iterator.next();
163 
164             for (MetadataGenerator generator : generators) {
165                 artifact = generator.transformArtifact(artifact);
166             }
167 
168             iterator.set(artifact);
169 
170             install(session, trace, artifact);
171             result.addArtifact(artifact);
172         }
173 
174         metadatas = Utils.finishMetadata(generators, artifacts);
175 
176         syncContext.acquire(null, metadatas);
177 
178         for (Metadata metadata : metadatas) {
179             install(session, trace, metadata);
180             processedMetadata.put(metadata, null);
181             result.addMetadata(metadata);
182         }
183 
184         for (Metadata metadata : request.getMetadata()) {
185             if (!processedMetadata.containsKey(metadata)) {
186                 install(session, trace, metadata);
187                 result.addMetadata(metadata);
188             }
189         }
190 
191         return result;
192     }
193 
194     private List<? extends MetadataGenerator> getMetadataGenerators(
195             RepositorySystemSession session, InstallRequest request) {
196         PrioritizedComponents<MetadataGeneratorFactory> factories =
197                 Utils.sortMetadataGeneratorFactories(session, this.metadataFactories);
198 
199         List<MetadataGenerator> generators = new ArrayList<>();
200 
201         for (PrioritizedComponent<MetadataGeneratorFactory> factory : factories.getEnabled()) {
202             MetadataGenerator generator = factory.getComponent().newInstance(session, request);
203             if (generator != null) {
204                 generators.add(generator);
205             }
206         }
207 
208         return generators;
209     }
210 
211     private void install(RepositorySystemSession session, RequestTrace trace, Artifact artifact)
212             throws InstallationException {
213         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
214 
215         File srcFile = artifact.getFile();
216 
217         Collection<FileTransformer> fileTransformers =
218                 session.getFileTransformerManager().getTransformersForArtifact(artifact);
219         if (fileTransformers.isEmpty()) {
220             install(session, trace, artifact, lrm, srcFile, null);
221         } else {
222             for (FileTransformer fileTransformer : fileTransformers) {
223                 install(session, trace, artifact, lrm, srcFile, fileTransformer);
224             }
225         }
226     }
227 
228     private void install(
229             RepositorySystemSession session,
230             RequestTrace trace,
231             Artifact artifact,
232             LocalRepositoryManager lrm,
233             File srcFile,
234             FileTransformer fileTransformer)
235             throws InstallationException {
236         final Artifact targetArtifact;
237         if (fileTransformer != null) {
238             targetArtifact = fileTransformer.transformArtifact(artifact);
239         } else {
240             targetArtifact = artifact;
241         }
242 
243         File dstFile = new File(lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact(targetArtifact));
244 
245         artifactInstalling(session, trace, targetArtifact, dstFile);
246 
247         Exception exception = null;
248         try {
249             if (dstFile.equals(srcFile)) {
250                 throw new IllegalStateException("cannot install " + dstFile + " to same path");
251             }
252 
253             boolean copy = "pom".equals(targetArtifact.getExtension())
254                     || srcFile.lastModified() != dstFile.lastModified()
255                     || srcFile.length() != dstFile.length()
256                     || !srcFile.exists();
257 
258             if (!copy) {
259                 LOGGER.debug("Skipped re-installing {} to {}, seems unchanged", srcFile, dstFile);
260             } else if (fileTransformer != null) {
261                 try (InputStream is = fileTransformer.transformData(srcFile)) {
262                     fileProcessor.write(dstFile, is);
263                     dstFile.setLastModified(srcFile.lastModified());
264                 }
265             } else {
266                 fileProcessor.copy(srcFile, dstFile);
267                 dstFile.setLastModified(srcFile.lastModified());
268             }
269 
270             lrm.add(session, new LocalArtifactRegistration(targetArtifact));
271         } catch (Exception e) {
272             exception = e;
273             throw new InstallationException("Failed to install artifact " + targetArtifact + ": " + e.getMessage(), e);
274         } finally {
275             artifactInstalled(session, trace, targetArtifact, dstFile, exception);
276         }
277     }
278 
279     private void install(RepositorySystemSession session, RequestTrace trace, Metadata metadata)
280             throws InstallationException {
281         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
282 
283         File dstFile = new File(lrm.getRepository().getBasedir(), lrm.getPathForLocalMetadata(metadata));
284 
285         metadataInstalling(session, trace, metadata, dstFile);
286 
287         Exception exception = null;
288         try {
289             if (metadata instanceof MergeableMetadata) {
290                 ((MergeableMetadata) metadata).merge(dstFile, dstFile);
291             } else {
292                 if (dstFile.equals(metadata.getFile())) {
293                     throw new IllegalStateException("cannot install " + dstFile + " to same path");
294                 }
295                 fileProcessor.copy(metadata.getFile(), dstFile);
296             }
297 
298             lrm.add(session, new LocalMetadataRegistration(metadata));
299         } catch (Exception e) {
300             exception = e;
301             throw new InstallationException("Failed to install metadata " + metadata + ": " + e.getMessage(), e);
302         } finally {
303             metadataInstalled(session, trace, metadata, dstFile, exception);
304         }
305     }
306 
307     private void artifactInstalling(
308             RepositorySystemSession session, RequestTrace trace, Artifact artifact, File dstFile) {
309         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLING);
310         event.setTrace(trace);
311         event.setArtifact(artifact);
312         event.setRepository(session.getLocalRepositoryManager().getRepository());
313         event.setFile(dstFile);
314 
315         repositoryEventDispatcher.dispatch(event.build());
316     }
317 
318     private void artifactInstalled(
319             RepositorySystemSession session, RequestTrace trace, Artifact artifact, File dstFile, Exception exception) {
320         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_INSTALLED);
321         event.setTrace(trace);
322         event.setArtifact(artifact);
323         event.setRepository(session.getLocalRepositoryManager().getRepository());
324         event.setFile(dstFile);
325         event.setException(exception);
326 
327         repositoryEventDispatcher.dispatch(event.build());
328     }
329 
330     private void metadataInstalling(
331             RepositorySystemSession session, RequestTrace trace, Metadata metadata, File dstFile) {
332         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLING);
333         event.setTrace(trace);
334         event.setMetadata(metadata);
335         event.setRepository(session.getLocalRepositoryManager().getRepository());
336         event.setFile(dstFile);
337 
338         repositoryEventDispatcher.dispatch(event.build());
339     }
340 
341     private void metadataInstalled(
342             RepositorySystemSession session, RequestTrace trace, Metadata metadata, File dstFile, Exception exception) {
343         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INSTALLED);
344         event.setTrace(trace);
345         event.setMetadata(metadata);
346         event.setRepository(session.getLocalRepositoryManager().getRepository());
347         event.setFile(dstFile);
348         event.setException(exception);
349 
350         repositoryEventDispatcher.dispatch(event.build());
351     }
352 }