1 package org.eclipse.aether.internal.impl.synccontext.named;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.eclipse.aether.RepositorySystemSession;
23 import org.eclipse.aether.SyncContext;
24 import org.eclipse.aether.artifact.Artifact;
25 import org.eclipse.aether.metadata.Metadata;
26 import org.eclipse.aether.named.NamedLock;
27 import org.eclipse.aether.named.NamedLockFactory;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 import java.util.ArrayDeque;
32 import java.util.Collection;
33 import java.util.Deque;
34 import java.util.Objects;
35 import java.util.concurrent.TimeUnit;
36
37
38
39
40 public final class NamedLockFactoryAdapter
41 {
42 private final NameMapper nameMapper;
43
44 private final NamedLockFactory namedLockFactory;
45
46 private final long time;
47
48 private final TimeUnit timeUnit;
49
50 public NamedLockFactoryAdapter( final NameMapper nameMapper, final NamedLockFactory namedLockFactory,
51 final long time, final TimeUnit timeUnit )
52 {
53 this.nameMapper = Objects.requireNonNull( nameMapper );
54 this.namedLockFactory = Objects.requireNonNull( namedLockFactory );
55 if ( time < 0L )
56 {
57 throw new IllegalArgumentException( "time cannot be negative" );
58 }
59 this.time = time;
60 this.timeUnit = Objects.requireNonNull( timeUnit );
61 }
62
63 public SyncContext newInstance( final RepositorySystemSession session, final boolean shared )
64 {
65 return new AdaptedLockSyncContext( session, shared, nameMapper, namedLockFactory, time, timeUnit );
66 }
67
68 public void shutdown()
69 {
70 namedLockFactory.shutdown();
71 }
72
73 private static class AdaptedLockSyncContext implements SyncContext
74 {
75 private static final Logger LOGGER = LoggerFactory.getLogger( AdaptedLockSyncContext.class );
76
77 private final RepositorySystemSession session;
78
79 private final boolean shared;
80
81 private final NameMapper lockNaming;
82
83 private final SessionAwareNamedLockFactory sessionAwareNamedLockFactory;
84
85 private final NamedLockFactory namedLockFactory;
86
87 private final long time;
88
89 private final TimeUnit timeUnit;
90
91 private final Deque<NamedLock> locks;
92
93 private AdaptedLockSyncContext( final RepositorySystemSession session, final boolean shared,
94 final NameMapper lockNaming, final NamedLockFactory namedLockFactory,
95 final long time, final TimeUnit timeUnit )
96 {
97 this.session = session;
98 this.shared = shared;
99 this.lockNaming = lockNaming;
100 this.sessionAwareNamedLockFactory = namedLockFactory instanceof SessionAwareNamedLockFactory
101 ? (SessionAwareNamedLockFactory) namedLockFactory : null;
102 this.namedLockFactory = namedLockFactory;
103 this.time = time;
104 this.timeUnit = timeUnit;
105 this.locks = new ArrayDeque<>();
106 }
107
108 @Override
109 public void acquire( Collection<? extends Artifact> artifacts, Collection<? extends Metadata> metadatas )
110 {
111 Collection<String> keys = lockNaming.nameLocks( session, artifacts, metadatas );
112 if ( keys.isEmpty() )
113 {
114 return;
115 }
116
117 LOGGER.trace( "Need {} {} lock(s) for {}", keys.size(), shared ? "read" : "write", keys );
118 int acquiredLockCount = 0;
119 for ( String key : keys )
120 {
121 NamedLock namedLock = sessionAwareNamedLockFactory != null ? sessionAwareNamedLockFactory
122 .getLock( session, key ) : namedLockFactory.getLock( key );
123 try
124 {
125 LOGGER.trace( "Acquiring {} lock for '{}'",
126 shared ? "read" : "write", key );
127
128 boolean locked;
129 if ( shared )
130 {
131 locked = namedLock.lockShared( time, timeUnit );
132 }
133 else
134 {
135 locked = namedLock.lockExclusively( time, timeUnit );
136 }
137
138 if ( !locked )
139 {
140 LOGGER.trace( "Failed to acquire {} lock for '{}'",
141 shared ? "read" : "write", key );
142
143 namedLock.close();
144 throw new IllegalStateException(
145 "Could not acquire " + ( shared ? "read" : "write" )
146 + " lock for '" + namedLock.name() + "'" );
147 }
148
149 locks.push( namedLock );
150 acquiredLockCount++;
151 }
152 catch ( InterruptedException e )
153 {
154 Thread.currentThread().interrupt();
155 throw new RuntimeException( e );
156 }
157 }
158 LOGGER.trace( "Total locks acquired: {}", acquiredLockCount );
159 }
160
161 @Override
162 public void close()
163 {
164 if ( locks.isEmpty() )
165 {
166 return;
167 }
168
169
170 int released = 0;
171 while ( !locks.isEmpty() )
172 {
173 try ( NamedLock namedLock = locks.pop() )
174 {
175 LOGGER.trace( "Releasing {} lock for '{}'",
176 shared ? "read" : "write", namedLock.name() );
177 namedLock.unlock();
178 released++;
179 }
180 }
181 LOGGER.trace( "Total locks released: {}", released );
182 }
183 }
184 }