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 try {
59 client.lock(Objects.requireNonNull(contextId), keys, time, unit);
60 } catch (TimeoutException e) {
61 tryUnlock(contextId);
62 return false;
63 }
64 contexts.push(new Ctx(true, contextId, true));
65 return true;
66 } catch (TimeoutException e) {
67 return false;
68 }
69 }
70
71 @Override
72 public boolean doLockExclusively(long time, TimeUnit unit) {
73 ArrayDeque<Ctx> contexts = this.contexts.get();
74 if (contexts.stream().anyMatch(c -> c.shared)) {
75 throw new LockUpgradeNotSupportedException(this);
76 }
77 if (!contexts.isEmpty()) {
78 contexts.push(new Ctx(false, null, false));
79 return true;
80 }
81 try {
82 String contextId = client.newContext(false, time, unit);
83 try {
84 client.lock(Objects.requireNonNull(contextId), keys, time, unit);
85 } catch (TimeoutException e) {
86 tryUnlock(contextId);
87 return false;
88 }
89 contexts.push(new Ctx(true, contextId, false));
90 return true;
91 } catch (TimeoutException e) {
92 return false;
93 }
94 }
95
96 @Override
97 public void doUnlock() {
98 ArrayDeque<Ctx> contexts = this.contexts.get();
99 if (contexts.isEmpty()) {
100 throw new IllegalStateException("improper boxing");
101 }
102 Ctx ctx = contexts.pop();
103 if (ctx.acted) {
104 client.unlock(ctx.contextId);
105 }
106 }
107
108 private void tryUnlock(String contextId) {
109 try {
110 client.unlock(contextId);
111 } catch (Exception e) {
112
113
114
115 }
116 }
117
118 private record Ctx(boolean acted, String contextId, boolean shared) {}
119 }