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.repository.internal;
20  
21  import java.util.Objects;
22  import java.util.concurrent.ConcurrentHashMap;
23  import java.util.concurrent.ConcurrentMap;
24  import java.util.function.Supplier;
25  
26  import org.apache.maven.building.Source;
27  import org.apache.maven.model.building.ModelCache;
28  import org.eclipse.aether.RepositoryCache;
29  import org.eclipse.aether.RepositorySystemSession;
30  
31  import static java.util.Objects.requireNonNull;
32  
33  /**
34   * A model builder cache backed by the repository system cache.
35   *
36   * @deprecated since 4.0.0, use {@code maven-api-impl} jar instead
37   */
38  @Deprecated(since = "4.0.0")
39  public class DefaultModelCache implements ModelCache {
40      private static final String KEY = DefaultModelCache.class.getName();
41  
42      @SuppressWarnings("unchecked")
43      public static ModelCache newInstance(RepositorySystemSession session) {
44          ConcurrentHashMap<Object, Supplier<?>> cache;
45          RepositoryCache repositoryCache = session.getCache();
46          if (repositoryCache == null) {
47              cache = new ConcurrentHashMap<>();
48          } else {
49              cache = (ConcurrentHashMap<Object, Supplier<?>>)
50                      repositoryCache.computeIfAbsent(session, KEY, ConcurrentHashMap::new);
51          }
52          return new DefaultModelCache(cache);
53      }
54  
55      private final ConcurrentMap<Object, Supplier<?>> cache;
56  
57      private DefaultModelCache(ConcurrentMap<Object, Supplier<?>> cache) {
58          this.cache = requireNonNull(cache);
59      }
60  
61      @Override
62      @SuppressWarnings({"unchecked"})
63      public <T> T computeIfAbsent(String groupId, String artifactId, String version, String tag, Supplier<T> data) {
64          return (T) computeIfAbsent(new GavCacheKey(groupId, artifactId, version, tag), data);
65      }
66  
67      @Override
68      @SuppressWarnings({"unchecked"})
69      public <T> T computeIfAbsent(Source path, String tag, Supplier<T> data) {
70          return (T) computeIfAbsent(new SourceCacheKey(path, tag), data);
71      }
72  
73      protected Object computeIfAbsent(Object key, Supplier<?> data) {
74          return cache.computeIfAbsent(key, k -> new CachingSupplier<>(data)).get();
75      }
76  
77      static class GavCacheKey {
78  
79          private final String gav;
80  
81          private final String tag;
82  
83          private final int hash;
84  
85          GavCacheKey(String groupId, String artifactId, String version, String tag) {
86              this(gav(groupId, artifactId, version), tag);
87          }
88  
89          GavCacheKey(String gav, String tag) {
90              this.gav = gav;
91              this.tag = tag;
92              this.hash = Objects.hash(gav, tag);
93          }
94  
95          private static String gav(String groupId, String artifactId, String version) {
96              StringBuilder sb = new StringBuilder();
97              if (groupId != null) {
98                  sb.append(groupId);
99              }
100             sb.append(":");
101             if (artifactId != null) {
102                 sb.append(artifactId);
103             }
104             sb.append(":");
105             if (version != null) {
106                 sb.append(version);
107             }
108             return sb.toString();
109         }
110 
111         @Override
112         public boolean equals(Object obj) {
113             if (this == obj) {
114                 return true;
115             }
116             if (null == obj || !getClass().equals(obj.getClass())) {
117                 return false;
118             }
119             GavCacheKey that = (GavCacheKey) obj;
120             return Objects.equals(this.gav, that.gav) && Objects.equals(this.tag, that.tag);
121         }
122 
123         @Override
124         public int hashCode() {
125             return hash;
126         }
127 
128         @Override
129         public String toString() {
130             return "GavCacheKey{" + "gav='" + gav + '\'' + ", tag='" + tag + '\'' + '}';
131         }
132     }
133 
134     private static final class SourceCacheKey {
135         private final Source source;
136 
137         private final String tag;
138 
139         private final int hash;
140 
141         SourceCacheKey(Source source, String tag) {
142             this.source = source;
143             this.tag = tag;
144             this.hash = Objects.hash(source, tag);
145         }
146 
147         @Override
148         public String toString() {
149             return "SourceCacheKey{" + "source=" + source + ", tag='" + tag + '\'' + '}';
150         }
151 
152         @Override
153         public boolean equals(Object obj) {
154             if (this == obj) {
155                 return true;
156             }
157             if (null == obj || !getClass().equals(obj.getClass())) {
158                 return false;
159             }
160             SourceCacheKey that = (SourceCacheKey) obj;
161             return Objects.equals(this.source, that.source) && Objects.equals(this.tag, that.tag);
162         }
163 
164         @Override
165         public int hashCode() {
166             return hash;
167         }
168     }
169 
170     static class CachingSupplier<T> implements Supplier<T> {
171         final Supplier<T> supplier;
172         volatile Object value;
173 
174         CachingSupplier(Supplier<T> supplier) {
175             this.supplier = supplier;
176         }
177 
178         @Override
179         @SuppressWarnings({"unchecked", "checkstyle:InnerAssignment"})
180         public T get() {
181             Object v;
182             if ((v = value) == null) {
183                 synchronized (this) {
184                     if ((v = value) == null) {
185                         try {
186                             v = value = supplier.get();
187                         } catch (Exception e) {
188                             v = value = new AltRes(e);
189                         }
190                     }
191                 }
192             }
193             if (v instanceof AltRes) {
194                 uncheckedThrow(((AltRes) v).t);
195             }
196             return (T) v;
197         }
198 
199         static class AltRes {
200             final Throwable t;
201 
202             AltRes(Throwable t) {
203                 this.t = t;
204             }
205         }
206     }
207 
208     @SuppressWarnings("unchecked")
209     static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
210         throw (T) t; // rely on vacuous cast
211     }
212 }