1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.named.ipc;
20
21 import java.util.ArrayDeque;
22 import java.util.Collection;
23 import java.util.Objects;
24 import java.util.concurrent.TimeUnit;
25 import java.util.concurrent.TimeoutException;
26
27 import org.eclipse.aether.named.NamedLockKey;
28 import org.eclipse.aether.named.support.LockUpgradeNotSupportedException;
29 import org.eclipse.aether.named.support.NamedLockSupport;
30
31
32
33
34
35
36 class IpcNamedLock extends NamedLockSupport {
37
38 final IpcClient client;
39 final Collection<String> keys;
40 final ThreadLocal<ArrayDeque<Ctx>> contexts;
41
42 IpcNamedLock(NamedLockKey key, IpcNamedLockFactory factory, IpcClient client, Collection<String> keys) {
43 super(key, factory);
44 this.client = client;
45 this.keys = keys;
46 this.contexts = ThreadLocal.withInitial(ArrayDeque::new);
47 }
48
49 @Override
50 public boolean doLockShared(long time, TimeUnit unit) {
51 ArrayDeque<Ctx> contexts = this.contexts.get();
52 if (!contexts.isEmpty()) {
53 contexts.push(new Ctx(false, null, true));
54 return true;
55 }
56 try {
57 String contextId = client.newContext(true, time, unit);
58 client.lock(Objects.requireNonNull(contextId), keys, time, unit);
59 contexts.push(new Ctx(true, contextId, true));
60 return true;
61 } catch (TimeoutException e) {
62 return false;
63 }
64 }
65
66 @Override
67 public boolean doLockExclusively(long time, TimeUnit unit) {
68 ArrayDeque<Ctx> contexts = this.contexts.get();
69 if (contexts.stream().anyMatch(c -> c.shared)) {
70 throw new LockUpgradeNotSupportedException(this);
71 }
72 if (!contexts.isEmpty()) {
73 contexts.push(new Ctx(false, null, false));
74 return true;
75 }
76 try {
77 String contextId = client.newContext(false, time, unit);
78 client.lock(Objects.requireNonNull(contextId), keys, time, unit);
79 contexts.push(new Ctx(true, contextId, false));
80 return true;
81 } catch (TimeoutException e) {
82 return false;
83 }
84 }
85
86 @Override
87 public void doUnlock() {
88 ArrayDeque<Ctx> contexts = this.contexts.get();
89 if (contexts.isEmpty()) {
90 throw new IllegalStateException("improper boxing");
91 }
92 Ctx ctx = contexts.pop();
93 if (ctx.acted) {
94 client.unlock(ctx.contextId);
95 }
96 }
97
98 private static final class Ctx {
99 private final boolean acted;
100 private final String contextId;
101 private final boolean shared;
102
103 private Ctx(boolean acted, String contextId, boolean shared) {
104 this.acted = acted;
105 this.contextId = contextId;
106 this.shared = shared;
107 }
108 }
109 }