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.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.LinkedHashSet;
27  import java.util.List;
28  import java.util.Objects;
29  import java.util.concurrent.atomic.AtomicReference;
30  
31  import org.eclipse.aether.artifact.Artifact;
32  import org.eclipse.aether.repository.WorkspaceReader;
33  import org.eclipse.aether.repository.WorkspaceRepository;
34  
35  import static java.util.Objects.requireNonNull;
36  
37  /**
38   * A workspace reader that delegates to a chain of other readers, effectively aggregating their contents.
39   */
40  public final class ChainedWorkspaceReader implements WorkspaceReader {
41      private final List<WorkspaceReader> readers;
42      private final AtomicReference<WorkspaceRepository> repository;
43  
44      /**
45       * Creates a new workspace reader by chaining the specified readers.
46       *
47       * @param readers the readers to chain, may be {@code null}
48       * @see #newInstance(WorkspaceReader, WorkspaceReader)
49       */
50      public ChainedWorkspaceReader(WorkspaceReader... readers) {
51          ArrayList<WorkspaceReader> list = new ArrayList<>();
52          if (readers != null) {
53              Arrays.stream(readers).filter(Objects::nonNull).forEach(list::add);
54          }
55          StringBuilder buffer = new StringBuilder();
56          for (WorkspaceReader reader : list) {
57              if (buffer.length() > 0) {
58                  buffer.append('+');
59              }
60              buffer.append(reader.getRepository().getContentType());
61          }
62          this.readers = Collections.unmodifiableList(list);
63          this.repository = new AtomicReference<>(new WorkspaceRepository(buffer.toString(), new Key(list)));
64      }
65  
66      /**
67       * Creates a new workspace reader by chaining the specified readers. In contrast to the constructor, this factory
68       * method will avoid creating an actual chained reader if one of the specified readers is actually {@code null}.
69       *
70       * @param reader1 the first workspace reader, may be {@code null}
71       * @param reader2 the second workspace reader, may be {@code null}
72       * @return the chained reader or {@code null} if no workspace reader was supplied
73       */
74      public static WorkspaceReader newInstance(WorkspaceReader reader1, WorkspaceReader reader2) {
75          if (reader1 == null) {
76              return reader2;
77          } else if (reader2 == null) {
78              return reader1;
79          }
80          return new ChainedWorkspaceReader(reader1, reader2);
81      }
82  
83      @Override
84      public File findArtifact(Artifact artifact) {
85          requireNonNull(artifact, "artifact cannot be null");
86          File file = null;
87  
88          for (WorkspaceReader reader : readers) {
89              file = reader.findArtifact(artifact);
90              if (file != null) {
91                  break;
92              }
93          }
94  
95          return file;
96      }
97  
98      @Override
99      public List<String> findVersions(Artifact artifact) {
100         requireNonNull(artifact, "artifact cannot be null");
101         Collection<String> versions = new LinkedHashSet<>();
102 
103         for (WorkspaceReader reader : readers) {
104             versions.addAll(reader.findVersions(artifact));
105         }
106 
107         return Collections.unmodifiableList(new ArrayList<>(versions));
108     }
109 
110     @Override
111     public WorkspaceRepository getRepository() {
112         Key key = new Key(readers);
113         return repository.updateAndGet(r -> {
114             if (!key.equals(r.getKey())) {
115                 return new WorkspaceRepository(r.getContentType(), key);
116             } else {
117                 return r;
118             }
119         });
120     }
121 
122     private static class Key {
123         private final List<Object> keys;
124 
125         Key(List<WorkspaceReader> readers) {
126             ArrayList<Object> keys = new ArrayList<>();
127             for (WorkspaceReader reader : readers) {
128                 keys.add(reader.getRepository().getKey());
129             }
130             this.keys = keys;
131         }
132 
133         @Override
134         public boolean equals(Object obj) {
135             if (this == obj) {
136                 return true;
137             }
138             if (obj == null || !getClass().equals(obj.getClass())) {
139                 return false;
140             }
141             return keys.equals(((Key) obj).keys);
142         }
143 
144         @Override
145         public int hashCode() {
146             return keys.hashCode();
147         }
148     }
149 }