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

openmrs / openmrs-core / 16357938490

17 Jul 2025 11:06PM UTC coverage: 65.244% (-0.1%) from 65.359%
16357938490

push

github

web-flow
TRUNK-6318: Add S3 Storage Service (#5110)

111 of 156 new or added lines in 5 files covered. (71.15%)

48 existing lines in 8 files now uncovered.

23568 of 36123 relevant lines covered (65.24%)

0.65 hits per line

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

81.82
/api/src/main/java/org/openmrs/api/storage/BaseStorageService.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.api.storage;
11

12
import java.io.File;
13
import java.io.IOException;
14
import java.io.InputStream;
15
import java.io.UnsupportedEncodingException;
16
import java.net.URLDecoder;
17
import java.net.URLEncoder;
18
import java.nio.file.Files;
19
import java.nio.file.Path;
20
import java.nio.file.Paths;
21
import java.nio.file.StandardCopyOption;
22
import java.time.LocalDateTime;
23
import java.time.format.DateTimeFormatter;
24

25
import org.apache.commons.lang3.RandomStringUtils;
26
import org.openmrs.api.StorageService;
27
import org.openmrs.api.impl.BaseOpenmrsService;
28
import org.openmrs.api.stream.StreamDataService;
29
import org.openmrs.api.stream.StreamDataWriter;
30
import org.springframework.beans.factory.annotation.Autowired;
31

32
/**
33
 * Implements temporary storage.
34
 * 
35
 * @since 2.8.0, 2.7.5, 2.6.16, 2.5.15
36
 */
37
public abstract class BaseStorageService extends BaseOpenmrsService implements StorageService {
38
        private final StreamDataService streamService;
39
        
40
        private final Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"));
1✔
41

42
        private final DateTimeFormatter keyDateTimeFormat = DateTimeFormatter.ofPattern("yyyy/MM-dd/yyyy-MM-dd-HH-mm-ss-SSS-");
1✔
43
        
44
        public BaseStorageService(@Autowired StreamDataService streamService) {
1✔
45
                this.streamService = streamService;
1✔
46
        }
1✔
47

48
        @Override
49
        public InputStream getTempData(String key) throws IOException {
50
                Path tempFile = tempDir.resolve(key);
1✔
51
                if (!Files.exists(tempFile)) {
1✔
52
                        throw new IOException("Temp file does not exist: " + key);
×
53
                }
54
                return Files.newInputStream(tempFile);
1✔
55
        }
56

57
        @Override
58
        public String saveData(InputStream inputStream, ObjectMetadata metadata, String moduleIdOrGroup) 
59
                throws IOException {
60
                return saveData(inputStream, metadata, moduleIdOrGroup, null);
1✔
61
        }
62
        
63

64
        public String saveData(StreamDataWriter dataWriter, ObjectMetadata metadata, String moduleIdOrGroup) 
65
                throws IOException {
66
                return saveData(dataWriter, metadata, moduleIdOrGroup, null);
1✔
67
        }
68

69
        public String saveData(StreamDataWriter dataWriter, ObjectMetadata metadata, String moduleIdOrGroup,
70
                                                   String keySuffix) throws IOException {
71
                return saveData(streamService.streamData(dataWriter, metadata != null ? metadata.getLength() : null), metadata, 
1✔
72
                        moduleIdOrGroup, keySuffix);
73
        }
74

75
        public String saveTempData(InputStream inputStream, ObjectMetadata metadata) throws IOException {
76
                Path tempFile = Files.createTempFile("openmrs-temp", ".tmp");
1✔
77
                Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
1✔
78
                tempFile.toFile().deleteOnExit();
1✔
79
                return tempFile.getFileName().toString();
1✔
80
        }
81

82
        public String saveTempData(StreamDataWriter writer, ObjectMetadata metadata) throws IOException {
83
                return saveTempData(streamService.streamData(writer, metadata != null ? metadata.getLength() : null), metadata);
×
84
        }
85

86
        protected String newKey(String moduleIdOrGroup, String keySuffix, String filename) {
87
                if (keySuffix == null) {
1✔
88
                        keySuffix = LocalDateTime.now().format(keyDateTimeFormat) + RandomStringUtils.insecure().nextAlphanumeric(8);
1✔
89
                }
90
                if (filename != null) {
1✔
91
                        keySuffix += '-' + filename.replace(File.separator, "");
1✔
92
                }
93
                
94
                if (moduleIdOrGroup == null) {
1✔
95
                        return keySuffix;
1✔
96
                } else {
97
                        if (!moduleIdOrGroupPattern.matcher(moduleIdOrGroup).matches()) {
1✔
98
                                throw new IllegalArgumentException("moduleIdOrGroup '" + moduleIdOrGroup + "' does not match [\\w-./]+");
1✔
99
                        }
100
                        return moduleIdOrGroup + '/' + keySuffix;
1✔
101
                }
102
        }
103

104
        protected String decodeKey(String key) {
105
                try {
106
                        return URLDecoder.decode(key, "UTF-8");
1✔
NEW
107
                } catch (UnsupportedEncodingException e) {
×
NEW
108
                        throw new RuntimeException(e);
×
109
                }
110
        }
111

112
        protected String encodeKey(String key) {
113
                try {
114
                        return URLEncoder.encode(key, "UTF-8").replace(".", "%2E")
1✔
115
                                .replace("*", "%2A").replace("%2F", "/");
1✔
NEW
116
                } catch (UnsupportedEncodingException e) {
×
NEW
117
                        throw new RuntimeException(e);
×
118
                }
119
        }
120
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc