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.apache.maven.buildcache.artifact;
20  
21  import java.io.File;
22  import java.util.concurrent.CompletableFuture;
23  import java.util.concurrent.ExecutionException;
24  import java.util.concurrent.Future;
25  import java.util.concurrent.RunnableFuture;
26  import java.util.function.Function;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.DefaultArtifact;
30  import org.apache.maven.artifact.InvalidArtifactRTException;
31  import org.apache.maven.artifact.handler.ArtifactHandler;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  import static java.util.Objects.requireNonNull;
36  
37  /**
38   * Overrides default file behavior with async file holder to restore files from cache lazy. Similar to {@link
39   * org.apache.maven.project.artifact.AttachedArtifact}
40   */
41  public class RestoredArtifact extends DefaultArtifact {
42  
43      private static final Logger LOGGER = LoggerFactory.getLogger(RestoredArtifact.class);
44      public static final String MSG_INTERRUPTED_WHILE_RETRIEVING_ARTIFACT_FILE =
45              "Interrupted while retrieving artifact file";
46      public static final String MSG_ERROR_RETRIEVING_ARTIFACT_FILE = "Error retrieving artifact file";
47  
48      private volatile Future<File> fileFuture;
49  
50      private Function<File, File> restoreToDiskConsumer;
51  
52      public RestoredArtifact(
53              Artifact parent,
54              Future<File> fileFuture,
55              String type,
56              String classifier,
57              ArtifactHandler handler,
58              Function<File, File> restoreToDiskConsumer) {
59          super(
60                  parent.getGroupId(),
61                  parent.getArtifactId(),
62                  parent.getVersionRange(),
63                  parent.getScope(),
64                  type,
65                  classifier,
66                  handler,
67                  parent.isOptional());
68          this.fileFuture = requireNonNull(fileFuture, "fileFuture == null");
69          this.restoreToDiskConsumer = restoreToDiskConsumer;
70      }
71  
72      /**
73       * Returns file using caller thread to download it if necessary
74       */
75      @Override
76      public File getFile() {
77  
78          if (!fileFuture.isDone()) {
79              if (fileFuture instanceof RunnableFuture) {
80                  try {
81                      LOGGER.trace(
82                              "Artifact file {} is not yet retrieved, downloading directly", getDependencyConflictId());
83                      ((RunnableFuture<?>) fileFuture).run();
84                  } catch (RuntimeException e) {
85                      throw new InvalidArtifactRTException(
86                              getGroupId(),
87                              getArtifactId(),
88                              getVersion(),
89                              getType(),
90                              MSG_ERROR_RETRIEVING_ARTIFACT_FILE,
91                              e);
92                  }
93              } else {
94                  LOGGER.trace(
95                          "Artifact file {} is not yet retrieved, waiting for download to complete",
96                          getDependencyConflictId());
97              }
98          }
99  
100         try {
101             File file = fileFuture.get();
102             return restoreToDiskConsumer.apply(file);
103         } catch (InterruptedException e) {
104             Thread.currentThread().interrupt();
105             throw new InvalidArtifactRTException(
106                     getGroupId(),
107                     getArtifactId(),
108                     getVersion(),
109                     getType(),
110                     MSG_INTERRUPTED_WHILE_RETRIEVING_ARTIFACT_FILE,
111                     e);
112         } catch (ExecutionException e) {
113             throw new InvalidArtifactRTException(
114                     getGroupId(),
115                     getArtifactId(),
116                     getVersion(),
117                     getType(),
118                     MSG_ERROR_RETRIEVING_ARTIFACT_FILE,
119                     e.getCause());
120         }
121     }
122 
123     @Override
124     public void setFile(File destination) {
125         this.fileFuture = CompletableFuture.completedFuture(destination);
126     }
127 }