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.util.repository;
20  
21  import java.io.File;
22  import java.nio.file.Files;
23  import java.nio.file.Path;
24  import java.util.List;
25  
26  import org.eclipse.aether.ConfigurationProperties;
27  import org.eclipse.aether.RepositorySystemSession;
28  import org.eclipse.aether.artifact.Artifact;
29  import org.eclipse.aether.metadata.Metadata;
30  import org.eclipse.aether.repository.LocalArtifactRegistration;
31  import org.eclipse.aether.repository.LocalArtifactRequest;
32  import org.eclipse.aether.repository.LocalArtifactResult;
33  import org.eclipse.aether.repository.LocalMetadataRegistration;
34  import org.eclipse.aether.repository.LocalMetadataRequest;
35  import org.eclipse.aether.repository.LocalMetadataResult;
36  import org.eclipse.aether.repository.LocalRepository;
37  import org.eclipse.aether.repository.LocalRepositoryManager;
38  import org.eclipse.aether.repository.RemoteRepository;
39  import org.eclipse.aether.util.ConfigUtils;
40  
41  import static java.util.Objects.requireNonNull;
42  import static java.util.stream.Collectors.toList;
43  
44  /**
45   * A local repository manager that chains multiple local repository managers: it directs all the write operations
46   * to chain head, while uses tail for {@link #find(RepositorySystemSession, LocalArtifactRequest)} and
47   * {@link #find(RepositorySystemSession, LocalMetadataRequest)} methods only. Hence, tail is used in resolving
48   * metadata and artifacts with or without (configurable) artifact availability tracking.
49   * <p>
50   * Implementation represents itself using the head local repository manager.
51   *
52   * @since 1.9.2
53   */
54  public final class ChainedLocalRepositoryManager implements LocalRepositoryManager {
55      private static final String CONFIG_PROPS_PREFIX = ConfigurationProperties.PREFIX_AETHER + "chainedLocalRepository.";
56  
57      /**
58       * When using chained local repository, should be the artifact availability ignored in tail.
59       *
60       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
61       * @configurationType {@link java.lang.Boolean}
62       * @configurationDefaultValue {@link #DEFAULT_IGNORE_TAIL_AVAILABILITY}
63       */
64      public static final String CONFIG_PROP_IGNORE_TAIL_AVAILABILITY = CONFIG_PROPS_PREFIX + "ignoreTailAvailability";
65  
66      public static final boolean DEFAULT_IGNORE_TAIL_AVAILABILITY = true;
67  
68      private final LocalRepositoryManager head;
69  
70      private final List<LocalRepositoryManager> tail;
71  
72      private final boolean ignoreTailAvailability;
73  
74      public ChainedLocalRepositoryManager(
75              LocalRepositoryManager head, List<LocalRepositoryManager> tail, boolean ignoreTailAvailability) {
76          this.head = requireNonNull(head, "head cannot be null");
77          this.tail = requireNonNull(tail, "tail cannot be null");
78          this.ignoreTailAvailability = ignoreTailAvailability;
79      }
80  
81      public ChainedLocalRepositoryManager(
82              LocalRepositoryManager head, List<LocalRepositoryManager> tail, RepositorySystemSession session) {
83          this.head = requireNonNull(head, "head cannot be null");
84          this.tail = requireNonNull(tail, "tail cannot be null");
85          this.ignoreTailAvailability =
86                  ConfigUtils.getBoolean(session, DEFAULT_IGNORE_TAIL_AVAILABILITY, CONFIG_PROP_IGNORE_TAIL_AVAILABILITY);
87      }
88  
89      @Override
90      public LocalRepository getRepository() {
91          return head.getRepository();
92      }
93  
94      @Override
95      public String getPathForLocalArtifact(Artifact artifact) {
96          return head.getPathForLocalArtifact(artifact);
97      }
98  
99      @Override
100     public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) {
101         return head.getPathForRemoteArtifact(artifact, repository, context);
102     }
103 
104     @Override
105     public String getPathForLocalMetadata(Metadata metadata) {
106         return head.getPathForLocalMetadata(metadata);
107     }
108 
109     @Override
110     public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) {
111         return head.getPathForRemoteMetadata(metadata, repository, context);
112     }
113 
114     @Override
115     public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) {
116         LocalArtifactResult result = head.find(session, request);
117         if (result.isAvailable()) {
118             return result;
119         }
120 
121         for (LocalRepositoryManager lrm : tail) {
122             result = lrm.find(session, request);
123             if (result.getFile() != null) {
124                 if (ignoreTailAvailability) {
125                     result.setAvailable(true);
126                     return result;
127                 } else if (result.isAvailable()) {
128                     return result;
129                 }
130             }
131         }
132         return new LocalArtifactResult(request);
133     }
134 
135     @Override
136     public void add(RepositorySystemSession session, LocalArtifactRegistration request) {
137         String artifactPath;
138         if (request.getRepository() != null) {
139             artifactPath = getPathForRemoteArtifact(request.getArtifact(), request.getRepository(), "check");
140         } else {
141             artifactPath = getPathForLocalArtifact(request.getArtifact());
142         }
143 
144         Path file = new File(head.getRepository().getBasedir(), artifactPath).toPath();
145         if (Files.isRegularFile(file)) {
146             head.add(session, request);
147         }
148     }
149 
150     @Override
151     public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) {
152         LocalMetadataResult result = head.find(session, request);
153         if (result.getFile() != null) {
154             return result;
155         }
156 
157         for (LocalRepositoryManager lrm : tail) {
158             result = lrm.find(session, request);
159             if (result.getFile() != null) {
160                 return result;
161             }
162         }
163         return new LocalMetadataResult(request);
164     }
165 
166     @Override
167     public void add(RepositorySystemSession session, LocalMetadataRegistration request) {
168         String metadataPath;
169         if (request.getRepository() != null) {
170             metadataPath = getPathForRemoteMetadata(request.getMetadata(), request.getRepository(), "check");
171         } else {
172             metadataPath = getPathForLocalMetadata(request.getMetadata());
173         }
174 
175         Path file = new File(head.getRepository().getBasedir(), metadataPath).toPath();
176         if (Files.isRegularFile(file)) {
177             head.add(session, request);
178         }
179     }
180 
181     @Override
182     public String toString() {
183         return head.getRepository().toString()
184                 + tail.stream().map(LocalRepositoryManager::getRepository).collect(toList());
185     }
186 }