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.resolver;
20  
21  import java.io.File;
22  import java.util.*;
23  import java.util.stream.Collectors;
24  
25  import org.apache.maven.api.model.Model;
26  import org.apache.maven.internal.impl.resolver.MavenWorkspaceReader;
27  import org.eclipse.aether.artifact.Artifact;
28  import org.eclipse.aether.repository.WorkspaceReader;
29  import org.eclipse.aether.repository.WorkspaceRepository;
30  
31  import static java.util.Objects.requireNonNull;
32  
33  /**
34   * A maven workspace reader that delegates to a chain of other readers, effectively aggregating their contents.
35   * <p>
36   * This class, while technically is not immutable, should be considered as such once set up. If not mutated, it is also
37   * thread-safe. <em>The mutation of this class instances should happen beforehand their use in session</em>.
38   */
39  public class MavenChainedWorkspaceReader implements MavenWorkspaceReader {
40  
41      protected List<WorkspaceReader> readers;
42      protected WorkspaceRepository repository;
43  
44      /**
45       * Creates a new workspace reader by chaining the specified readers.
46       *
47       * @param readers The readers to chain must not be {@code null}.
48       */
49      public MavenChainedWorkspaceReader(WorkspaceReader... readers) {
50          setReaders(Arrays.asList(readers));
51      }
52  
53      @Override
54      public WorkspaceRepository getRepository() {
55          return this.repository;
56      }
57  
58      @Override
59      public Model findModel(Artifact artifact) {
60          requireNonNull(artifact, "artifact cannot be null");
61          Model model = null;
62  
63          for (WorkspaceReader workspaceReader : readers) {
64              if (workspaceReader instanceof MavenWorkspaceReader) {
65                  model = ((MavenWorkspaceReader) workspaceReader).findModel(artifact);
66                  if (model != null) {
67                      break;
68                  }
69              }
70          }
71  
72          return model;
73      }
74  
75      @Override
76      public File findArtifact(Artifact artifact) {
77          requireNonNull(artifact, "artifact cannot be null");
78          File file = null;
79  
80          for (WorkspaceReader reader : readers) {
81              file = reader.findArtifact(artifact);
82              if (file != null) {
83                  break;
84              }
85          }
86  
87          return file;
88      }
89  
90      @Override
91      public List<String> findVersions(Artifact artifact) {
92          requireNonNull(artifact, "artifact cannot be null");
93          Collection<String> versions = new LinkedHashSet<>();
94  
95          for (WorkspaceReader reader : readers) {
96              versions.addAll(reader.findVersions(artifact));
97          }
98  
99          return Collections.unmodifiableList(new ArrayList<>(versions));
100     }
101 
102     public void setReaders(Collection<WorkspaceReader> readers) {
103         requireNonNull(readers, "readers");
104         // skip possible null entries
105         this.readers = Collections.unmodifiableList(
106                 new ArrayList<>(readers.stream().filter(Objects::nonNull).collect(Collectors.toList())));
107         Key key = new Key(this.readers);
108         this.repository = new WorkspaceRepository(key.getContentType(), key);
109     }
110 
111     public List<WorkspaceReader> getReaders() {
112         return readers;
113     }
114 
115     public void addReader(WorkspaceReader workspaceReader) {
116         requireNonNull(workspaceReader, "workspaceReader");
117         ArrayList<WorkspaceReader> newReaders = new ArrayList<>(this.readers);
118         newReaders.add(workspaceReader);
119         setReaders(newReaders);
120     }
121 
122     private static class Key {
123         private final List<Object> keys;
124         private final String type;
125 
126         Key(Collection<WorkspaceReader> readers) {
127             keys = readers.stream().map(r -> r.getRepository().getKey()).collect(Collectors.toList());
128             type = readers.stream().map(r -> r.getRepository().getContentType()).collect(Collectors.joining("+"));
129         }
130 
131         public String getContentType() {
132             return type;
133         }
134 
135         public boolean equals(Object obj) {
136             if (this == obj) {
137                 return true;
138             } else {
139                 return obj != null && this.getClass().equals(obj.getClass()) && this.keys.equals(((Key) obj).keys);
140             }
141         }
142 
143         public int hashCode() {
144             return this.keys.hashCode();
145         }
146     }
147 
148     /**
149      * chains a collection of {@link WorkspaceReader}s
150      * @param workspaceReaderCollection the collection of readers, might be empty but never <code>null</code>
151      * @return if the collection contains only one item returns the single item, otherwise creates a new
152      *         {@link MavenChainedWorkspaceReader} chaining all readers in the order of the given collection.
153      */
154     public static WorkspaceReader of(Collection<WorkspaceReader> workspaceReaderCollection) {
155         WorkspaceReader[] readers = workspaceReaderCollection.toArray(new WorkspaceReader[0]);
156         if (readers.length == 1) {
157             return readers[0];
158         }
159         return new MavenChainedWorkspaceReader(readers);
160     }
161 }