1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.impl.synccontext.named;
20
21 import java.util.Collection;
22 import java.util.stream.Collectors;
23
24 import org.eclipse.aether.RepositorySystemSession;
25 import org.eclipse.aether.artifact.Artifact;
26 import org.eclipse.aether.metadata.Metadata;
27 import org.eclipse.aether.named.NamedLockKey;
28 import org.eclipse.aether.util.ConfigUtils;
29 import org.eclipse.aether.util.StringDigestUtil;
30
31 import static java.util.Objects.requireNonNull;
32
33
34
35
36
37
38
39
40
41
42
43 public class HashingNameMapper implements NameMapper {
44
45
46
47
48
49
50
51 public static final String CONFIG_PROP_DEPTH = NamedLockFactoryAdapter.CONFIG_PROPS_PREFIX + "hashing.depth";
52
53 public static final int DEFAULT_DEPTH = 2;
54
55 private final NameMapper delegate;
56
57 public HashingNameMapper(final NameMapper delegate) {
58 this.delegate = requireNonNull(delegate);
59 }
60
61 @Override
62 public boolean isFileSystemFriendly() {
63 return true;
64 }
65
66 @Override
67 public Collection<NamedLockKey> nameLocks(
68 RepositorySystemSession session,
69 Collection<? extends Artifact> artifacts,
70 Collection<? extends Metadata> metadatas) {
71 final int depth = ConfigUtils.getInteger(session, DEFAULT_DEPTH, CONFIG_PROP_DEPTH);
72 if (depth < 0 || depth > 4) {
73 throw new IllegalArgumentException("allowed depth value is between 0 and 4 (inclusive)");
74 }
75 return delegate.nameLocks(session, artifacts, metadatas).stream()
76 .map(k -> NamedLockKey.of(hashName(k.name(), depth), k.resources()))
77 .collect(Collectors.toList());
78 }
79
80 private String hashName(final String name, final int depth) {
81 String hashedName = StringDigestUtil.sha1(name);
82 if (depth == 0) {
83 return hashedName;
84 }
85 StringBuilder prefix = new StringBuilder();
86 int i = 0;
87 while (i < hashedName.length() && i / 2 < depth) {
88 prefix.append(hashedName, i, i + 2).append("/");
89 i += 2;
90 }
91 return prefix.append(hashedName).toString();
92 }
93 }