• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tomdesair / tus-java-server / 31911392528

15 Aug 2026 10:09PM UTC coverage: 94.941% (-0.8%) from 95.768%
31911392528

push

github

web-flow
fix(ci): update maven-dependency-submission-action to v5.0.0 (#115)

* fix(ci): update maven-dependency-submission-action to v5.0.0

* fix: Code duplication

2059 of 2312 branches covered (89.06%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

44 existing lines in 7 files now uncovered.

4603 of 4705 relevant lines covered (97.83%)

6.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.75
/src/main/java/me/desair/tus/server/upload/cache/ThreadLocalCachedStorageAndLockingService.java
1
package me.desair.tus.server.upload.cache;
2

3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.io.OutputStream;
6
import java.lang.ref.WeakReference;
7
import java.util.Objects;
8
import me.desair.tus.server.checksum.ChecksumAlgorithm;
9
import me.desair.tus.server.exception.TusException;
10
import me.desair.tus.server.exception.UploadNotFoundException;
11
import me.desair.tus.server.upload.UploadId;
12
import me.desair.tus.server.upload.UploadIdFactory;
13
import me.desair.tus.server.upload.UploadInfo;
14
import me.desair.tus.server.upload.UploadLock;
15
import me.desair.tus.server.upload.UploadLockingService;
16
import me.desair.tus.server.upload.UploadStorageService;
17
import me.desair.tus.server.upload.concatenation.UploadConcatenationService;
18

19
/**
20
 * Combined implementation of {@link UploadStorageService} and {@link UploadLockingService}. Uses
21
 * both of them as delegates but allowing to reduce disk operations during a request processing by
22
 * caching UploadInfo in the memory. UploadLockingService service is used as a delegate to cleanup
23
 * cached data on releasing a lock.
24
 */
25
public class ThreadLocalCachedStorageAndLockingService
26
    implements UploadLockingService, UploadStorageService {
27

28
  private final ThreadLocal<WeakReference<UploadInfo>> uploadInfoCache = new ThreadLocal<>();
10✔
29
  private final UploadLockingService lockingServiceDelegate;
30
  private final UploadStorageService storageServiceDelegate;
31
  private UploadIdFactory idFactory;
32

33
  /** Constructor of ThreadLocalCachedStorageAndLockingService. */
34
  public ThreadLocalCachedStorageAndLockingService(
35
      UploadStorageService storageServiceDelegate, UploadLockingService lockingServiceDelegate) {
4✔
36
    if (storageServiceDelegate.getClass() == ThreadLocalCachedStorageAndLockingService.class) {
8✔
37
      this.storageServiceDelegate =
12✔
38
          ((ThreadLocalCachedStorageAndLockingService) storageServiceDelegate)
39
              .storageServiceDelegate;
40
    } else {
41
      this.storageServiceDelegate = storageServiceDelegate;
6✔
42
    }
43
    if (lockingServiceDelegate.getClass() == ThreadLocalCachedStorageAndLockingService.class) {
8✔
44
      this.lockingServiceDelegate =
12✔
45
          ((ThreadLocalCachedStorageAndLockingService) lockingServiceDelegate)
46
              .lockingServiceDelegate;
47
    } else {
48
      this.lockingServiceDelegate = lockingServiceDelegate;
6✔
49
    }
50
  }
2✔
51

52
  @Override
53
  public UploadInfo getUploadInfo(UploadId id) throws IOException {
54
    if (id == null) {
4✔
55
      return null;
4✔
56
    }
57
    UploadInfo uploadInfo;
58
    WeakReference<UploadInfo> ref = uploadInfoCache.get();
10✔
59
    if (ref == null || (uploadInfo = ref.get()) == null || !id.equals(uploadInfo.getId())) {
26✔
60
      uploadInfo = storageServiceDelegate.getUploadInfo(id);
10✔
61
      uploadInfoCache.set(new WeakReference<>(uploadInfo));
14✔
62
    }
63
    return uploadInfo;
4✔
64
  }
65

66
  @Override
67
  public UploadInfo getUploadInfo(String uploadUrl, String ownerKey) throws IOException {
68
    UploadInfo uploadInfo = getUploadInfo(idFactory.readUploadId(uploadUrl));
14✔
69
    if (uploadInfo == null || !Objects.equals(uploadInfo.getOwnerKey(), ownerKey)) {
14✔
70
      uploadInfo = storageServiceDelegate.getUploadInfo(uploadUrl, ownerKey);
12✔
71
      uploadInfoCache.set(new WeakReference<>(uploadInfo));
14✔
72
    }
73
    return uploadInfo;
4✔
74
  }
75

76
  @Override
77
  public void update(UploadInfo uploadInfo) throws IOException, UploadNotFoundException {
78
    storageServiceDelegate.update(uploadInfo);
8✔
79
    uploadInfoCache.set(new WeakReference<>(uploadInfo));
14✔
80
  }
2✔
81

82
  @Override
83
  public void setIdFactory(UploadIdFactory idFactory) {
84
    this.idFactory = idFactory;
6✔
85
    this.storageServiceDelegate.setIdFactory(idFactory);
8✔
86
    this.lockingServiceDelegate.setIdFactory(idFactory);
8✔
87
  }
2✔
88

89
  @Override
90
  public String getUploadUri() {
91
    return storageServiceDelegate.getUploadUri();
8✔
92
  }
93

94
  @Override
95
  public UploadInfo append(UploadInfo upload, InputStream inputStream)
96
      throws IOException, TusException {
97
    UploadInfo info = storageServiceDelegate.append(upload, inputStream);
12✔
98
    uploadInfoCache.set(new WeakReference<>(info));
14✔
99
    return info;
4✔
100
  }
101

102
  @Override
103
  public void setMaxUploadSize(Long maxUploadSize) {
104
    storageServiceDelegate.setMaxUploadSize(maxUploadSize);
8✔
105
  }
2✔
106

107
  @Override
108
  public long getMaxUploadSize() {
109
    return storageServiceDelegate.getMaxUploadSize();
8✔
110
  }
111

112
  @Override
113
  public void setMaxAppendSize(Long maxAppendSize) {
114
    storageServiceDelegate.setMaxAppendSize(maxAppendSize);
4✔
115
  }
1✔
116

117
  @Override
118
  public Long getMaxAppendSize() {
119
    return storageServiceDelegate.getMaxAppendSize();
8✔
120
  }
121

122
  @Override
123
  public void setMinAppendSize(Long minAppendSize) {
124
    storageServiceDelegate.setMinAppendSize(minAppendSize);
4✔
125
  }
1✔
126

127
  @Override
128
  public Long getMinAppendSize() {
129
    return storageServiceDelegate.getMinAppendSize();
8✔
130
  }
131

132
  @Override
133
  public void setMinSize(Long minSize) {
134
    storageServiceDelegate.setMinSize(minSize);
4✔
135
  }
1✔
136

137
  @Override
138
  public Long getMinSize() {
139
    return storageServiceDelegate.getMinSize();
8✔
140
  }
141

142
  @Override
143
  public UploadInfo create(UploadInfo info, String ownerKey) throws IOException {
144
    UploadInfo uploadInfo = storageServiceDelegate.create(info, ownerKey);
12✔
145
    uploadInfoCache.set(new WeakReference<>(uploadInfo));
14✔
146
    return uploadInfo;
4✔
147
  }
148

149
  @Override
150
  public InputStream getUploadedBytes(String uploadUri, String ownerKey)
151
      throws IOException, UploadNotFoundException {
152
    return storageServiceDelegate.getUploadedBytes(uploadUri, ownerKey);
12✔
153
  }
154

155
  @Override
156
  public InputStream getUploadedBytes(UploadId id) throws IOException, UploadNotFoundException {
157
    return storageServiceDelegate.getUploadedBytes(id);
10✔
158
  }
159

160
  @Override
161
  public void copyUploadTo(UploadInfo info, OutputStream outputStream)
162
      throws UploadNotFoundException, IOException {
163
    storageServiceDelegate.copyUploadTo(info, outputStream);
10✔
164
    uploadInfoCache.set(new WeakReference<>(info));
14✔
165
  }
2✔
166

167
  @Override
168
  public void cleanupExpiredUploads(UploadLockingService uploadLockingService) throws IOException {
169
    storageServiceDelegate.cleanupExpiredUploads(uploadLockingService);
8✔
170
    // Since any cached uploads was potentially removed by the storage service
171
    // we clean the cache to prevent any stale state
172
    cleanupCache();
4✔
173
  }
2✔
174

175
  @Override
176
  public void removeLastNumberOfBytes(UploadInfo uploadInfo, long byteCount)
177
      throws UploadNotFoundException, IOException {
178
    storageServiceDelegate.removeLastNumberOfBytes(uploadInfo, byteCount);
10✔
179
    uploadInfoCache.set(new WeakReference<>(uploadInfo));
14✔
180
  }
2✔
181

182
  @Override
183
  public void terminateUpload(UploadInfo uploadInfo) throws UploadNotFoundException, IOException {
184
    storageServiceDelegate.terminateUpload(uploadInfo);
8✔
185
    // Since the upload is terminated and potentially removed by the storage service
186
    // we clean the cache to prevent any stale state
187
    cleanupCache();
4✔
188
  }
2✔
189

190
  @Override
191
  public Long getUploadExpirationPeriod() {
192
    return storageServiceDelegate.getUploadExpirationPeriod();
8✔
193
  }
194

195
  @Override
196
  public void setUploadExpirationPeriod(Long uploadExpirationPeriod) {
197
    storageServiceDelegate.setUploadExpirationPeriod(uploadExpirationPeriod);
8✔
198
  }
2✔
199

200
  @Override
201
  public void setUploadConcatenationService(UploadConcatenationService concatenationService) {
202
    storageServiceDelegate.setUploadConcatenationService(concatenationService);
8✔
203
  }
2✔
204

205
  @Override
206
  public UploadConcatenationService getUploadConcatenationService() {
207
    return storageServiceDelegate.getUploadConcatenationService();
8✔
208
  }
209

210
  @Override
211
  public void setUploadDeduplicationEnabled(boolean enabled) {
212
    storageServiceDelegate.setUploadDeduplicationEnabled(enabled);
8✔
213
  }
2✔
214

215
  @Override
216
  public boolean isUploadDeduplicationEnabled() {
217
    return storageServiceDelegate.isUploadDeduplicationEnabled();
8✔
218
  }
219

220
  @Override
221
  public void setJsonSerializationEnabled(boolean enabled) {
222
    storageServiceDelegate.setJsonSerializationEnabled(enabled);
4✔
223
  }
1✔
224

225
  @Override
226
  public boolean isJsonSerializationEnabled() {
227
    return storageServiceDelegate.isJsonSerializationEnabled();
4✔
228
  }
229

230
  @Override
231
  public UploadInfo getUploadInfoByChecksum(String checksum, ChecksumAlgorithm algorithm)
232
      throws IOException {
233
    return storageServiceDelegate.getUploadInfoByChecksum(checksum, algorithm);
12✔
234
  }
235

236
  @Override
237
  public UploadLock lockUploadByUri(String requestUri) throws TusException, IOException {
238
    UploadLock uploadLock = lockingServiceDelegate.lockUploadByUri(requestUri);
10✔
239
    return new CachedLock(uploadLock);
12✔
240
  }
241

242
  @Override
243
  public void cleanupStaleLocks() throws IOException {
244
    lockingServiceDelegate.cleanupStaleLocks();
6✔
245
    cleanupCache();
4✔
246
  }
2✔
247

248
  @Override
249
  public boolean isLocked(UploadId id) {
250
    return lockingServiceDelegate.isLocked(id);
10✔
251
  }
252

253
  @Override
254
  public void registerInputStream(String requestUri, InputStream inputStream) {
255
    lockingServiceDelegate.registerInputStream(requestUri, inputStream);
10✔
256
  }
2✔
257

258
  @Override
259
  public void requestLockRelease(String requestUri) {
260
    lockingServiceDelegate.requestLockRelease(requestUri);
8✔
261
  }
2✔
262

263
  @Override
264
  public void close() throws IOException {
265
    lockingServiceDelegate.close();
3✔
266
    storageServiceDelegate.close();
3✔
267
    cleanupCache();
2✔
268
  }
1✔
269

270
  private void cleanupCache() {
271
    WeakReference<UploadInfo> ref = uploadInfoCache.get();
10✔
272
    if (ref != null) {
4✔
273
      uploadInfoCache.remove();
6✔
274
      ref.clear();
4✔
275
    }
276
  }
2✔
277

278
  class CachedLock implements UploadLock {
279

280
    private final UploadLock delegate;
281

282
    CachedLock(UploadLock delegate) {
10✔
283
      this.delegate = delegate;
6✔
284
    }
2✔
285

286
    @Override
287
    public String getUploadUri() {
UNCOV
288
      return delegate != null ? delegate.getUploadUri() : null;
×
289
    }
290

291
    @Override
292
    public void release() {
UNCOV
293
      if (delegate != null) {
×
UNCOV
294
        delegate.release();
×
295
      }
UNCOV
296
    }
×
297

298
    @Override
299
    public void close() throws IOException {
300
      if (delegate != null) {
6✔
301
        delegate.close();
6✔
302
      }
303
      cleanupCache();
6✔
304
    }
2✔
305
  }
306
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc