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