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