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