1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.named.support;
20
21 import java.util.ArrayDeque;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26 import java.util.concurrent.TimeUnit;
27
28 import org.eclipse.aether.named.NamedLock;
29 import org.eclipse.aether.named.NamedLockKey;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33
34
35
36
37
38
39 public final class CompositeNamedLock extends NamedLockSupport {
40 private static final Logger LOGGER = LoggerFactory.getLogger(CompositeNamedLock.class);
41
42 private final Map<NamedLockKey, NamedLock> locks;
43
44 private final ArrayDeque<ArrayDeque<NamedLock>> steps = new ArrayDeque<>();
45
46 public CompositeNamedLock(NamedLockKey key, NamedLockFactorySupport factory, Collection<NamedLock> namedLocks) {
47 super(key, factory);
48 LinkedHashMap<NamedLockKey, NamedLock> map = new LinkedHashMap<>();
49 namedLocks.forEach(l -> map.put(l.key(), l));
50 this.locks = Collections.unmodifiableMap(map);
51 }
52
53 @Override
54 protected boolean doLockShared(long time, TimeUnit unit) throws InterruptedException {
55 return lock(time, unit, true);
56 }
57
58 @Override
59 protected boolean doLockExclusively(long time, TimeUnit unit) throws InterruptedException {
60 return lock(time, unit, false);
61 }
62
63 private boolean lock(long time, TimeUnit timeUnit, boolean shared) throws InterruptedException {
64 final ArrayDeque<NamedLock> step = new ArrayDeque<>(locks.size());
65 final String timeStr = time + " " + timeUnit;
66 final String lockKind = shared ? "shared" : "exclusive";
67 LOGGER.trace(
68 "{}: Need {} {} lock(s) of {} in {}", key().name(), locks.size(), lockKind, key().resources(), timeStr);
69 for (NamedLock namedLock : locks.values()) {
70 LOGGER.trace("{}: Acquiring {} lock for '{}'", key().name(), lockKind, namedLock.key());
71
72 boolean locked;
73 if (shared) {
74 locked = namedLock.lockShared(time, timeUnit);
75 } else {
76 locked = namedLock.lockExclusively(time, timeUnit);
77 }
78
79 if (!locked) {
80 LOGGER.trace(
81 "{}: Failed to acquire {} lock for '{}' in {}",
82 key().name(),
83 lockKind,
84 namedLock.key(),
85 timeStr);
86
87 unlockAll(step);
88 break;
89 } else {
90 step.push(namedLock);
91 }
92 }
93 if (step.size() == locks.size()) {
94 steps.push(step);
95 return true;
96 }
97 unlockAll(step);
98 return false;
99 }
100
101 @Override
102 protected void doUnlock() {
103 unlockAll(steps.pop());
104 }
105
106 @Override
107 protected void doClose() {
108 locks.values().forEach(NamedLock::close);
109 }
110
111 private void unlockAll(final ArrayDeque<NamedLock> locks) {
112 if (locks.isEmpty()) {
113 return;
114 }
115
116
117 while (!locks.isEmpty()) {
118 NamedLock namedLock = locks.pop();
119 LOGGER.trace("{}: Releasing lock for '{}'", key().name(), namedLock.key());
120 namedLock.unlock();
121 }
122 }
123 }