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

openmrs / openmrs-core / 13853363634

14 Mar 2025 09:10AM UTC coverage: 65.081% (+0.1%) from 64.959%
13853363634

push

github

web-flow
TRUNK-6304 Refactor code to use Storage Service (#4944)

* TRUNK-6300 Add Storage Service

* TRUNK-6304 Refactor code to use Storage Service

319 of 401 new or added lines in 13 files covered. (79.55%)

17 existing lines in 4 files now uncovered.

23407 of 35966 relevant lines covered (65.08%)

0.65 hits per line

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

91.8
/api/src/main/java/org/openmrs/obs/handler/ImageHandler.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.obs.handler;
11

12
import javax.imageio.ImageIO;
13
import javax.imageio.ImageReadParam;
14
import javax.imageio.ImageReader;
15
import javax.imageio.stream.ImageInputStream;
16
import java.awt.image.BufferedImage;
17
import java.io.ByteArrayInputStream;
18
import java.io.IOException;
19
import java.io.InputStream;
20
import java.io.UncheckedIOException;
21
import java.util.Collections;
22
import java.util.HashSet;
23
import java.util.Iterator;
24
import java.util.Set;
25

26
import org.apache.commons.io.FilenameUtils;
27
import org.openmrs.Obs;
28
import org.openmrs.api.APIException;
29
import org.openmrs.api.storage.ObjectMetadata;
30
import org.openmrs.obs.ComplexData;
31
import org.openmrs.obs.ComplexObsHandler;
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
34
import org.springframework.stereotype.Component;
35

36
/**
37
 * Handler for storing basic images for complex obs to the file system. The image mime type used is
38
 * taken from the image name. if the .* image name suffix matches
39
 * {@link javax.imageio.ImageIO#getWriterFormatNames()} then that mime type will be used to save the
40
 * image. Images are stored in the location specified by the global property: "obs.complex_obs_dir"
41
 * 
42
 * @see org.openmrs.util.OpenmrsConstants#GLOBAL_PROPERTY_COMPLEX_OBS_DIR
43
 * @since 1.5
44
 */
45
@Component
46
public class ImageHandler extends AbstractHandler implements ComplexObsHandler {
47
        
48
        /** Views supported by this handler */
49
        private static final String[] supportedViews = { ComplexObsHandler.RAW_VIEW };
1✔
50
        
51
        private static final Logger log = LoggerFactory.getLogger(ImageHandler.class);
1✔
52
        
53
        private Set<String> extensions;
54
        
55
        /**
56
         * Constructor initializes formats for alternative file names to protect from unintentionally
57
         * overwriting existing files.
58
         */
59
        public ImageHandler() {
60
                super();
1✔
61
                
62
                // Create a HashSet to quickly check for supported extensions.
63
                extensions = new HashSet<>();
1✔
64
                Collections.addAll(extensions, ImageIO.getWriterFormatNames());
1✔
65
        }
1✔
66
        
67
        /**
68
         * Currently supports all views and puts the Image file data into the ComplexData object
69
         * 
70
         * @see org.openmrs.obs.ComplexObsHandler#getObs(org.openmrs.Obs, java.lang.String)
71
         */
72
        @Override
73
        public Obs getObs(Obs obs, String view) {
74
                String key = parseDataKey(obs);
1✔
75
                
76
                // Raw image
77
                if (ComplexObsHandler.RAW_VIEW.equals(view)) {
1✔
78
                        String mimeType = null;
1✔
79
                        BufferedImage img = null;
1✔
80
                        try (InputStream in = storageService.getData(key)) {
1✔
81
                                ImageInputStream imageIn = ImageIO.createImageInputStream(in);
1✔
82
                                Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageIn);
1✔
83
                                if (imageReaders.hasNext()) {
1✔
84
                                        ImageReader imgReader = imageReaders.next();
1✔
85
                                        mimeType = "image/" + imgReader.getFormatName().toLowerCase();
1✔
86
                                        ImageReadParam param = imgReader.getDefaultReadParam();
1✔
87
                                        imgReader.setInput(imageIn, true, true);
1✔
88
                                        try {
89
                                                img = imgReader.read(0, param);
1✔
90
                                        } finally {
91
                                                imgReader.dispose();
1✔
92
                                        }
93
                                }
94
                        } catch (IOException e) {
1✔
95
                                log.error("Trying to read file: {}", key, e);
1✔
96
                                // Do not fail if image is missing
97
                        }
1✔
98
                        
99
                        ComplexData complexData = new ComplexData(key, img);
1✔
100
                        complexData.setMimeType(mimeType); // Set mimeType based on file content and not filename
1✔
101
                        if (img != null) { // Do not inject if image is missing
1✔
102
                                injectMissingMetadata(key, complexData);
1✔
103
                        }
104
                        complexData.setLength(null); // Reset as loaded image size is not equal to file size
1✔
105
                        
106
                        obs.setComplexData(complexData);
1✔
107
                } else {
1✔
108
                        // No other view supported
109
                        // NOTE: if adding support for another view, don't forget to update supportedViews list above
110
                        return null;
1✔
111
                }
112
                
113
                return obs;
1✔
114
        }
115
        
116
        /**
117
         * @see org.openmrs.obs.ComplexObsHandler#getSupportedViews()
118
         */
119
        @Override
120
        public String[] getSupportedViews() {
121
                return supportedViews;
1✔
122
        }
123
        
124
        /**
125
         * @see org.openmrs.obs.ComplexObsHandler#saveObs(org.openmrs.Obs)
126
         */
127
        @Override
128
        public Obs saveObs(Obs obs) throws APIException {
129
                try {
130
                        String[] splitTitle = obs.getComplexData().getTitle().split("\\|");
1✔
131
                        String filename = splitTitle[0];
1✔
132
                        if (splitTitle.length > 1) {
1✔
NEW
133
                                filename = splitTitle[1];
×
134
                        }
135
                        String extension = FilenameUtils.getExtension(filename);
1✔
136
                        String assignedKey = storageService.saveData((out) -> {
1✔
137
                                Object data = obs.getComplexData().getData();
1✔
138
                                
139
                                InputStream in = null;
1✔
140
                                if (data instanceof byte[]) {
1✔
141
                                        in = new ByteArrayInputStream((byte[]) data);
1✔
142
                                } else if (data instanceof InputStream) {
1✔
NEW
143
                                        in = (InputStream) data;
×
144
                                }
145
                                
146
                                BufferedImage img = null;
1✔
147
                                if (in != null) {
1✔
148
                                        img = ImageIO.read(in);
1✔
149
                                } else if (data instanceof BufferedImage) {
1✔
150
                                        img = (BufferedImage) data;
1✔
151
                                }
152
                                
153
                                if (img == null) {
1✔
NEW
154
                                        throw new APIException("Obs.error.cannot.save.complex", new Object[] { obs.getObsId() });
×
155
                                }
156
                                ImageIO.write(img, extension, out);
1✔
157
                                out.flush();
1✔
158
                        }, ObjectMetadata.builder().setFilename(filename).build(), getObsDir());
1✔
159

160
                        // Set the Title and URI for the valueComplex
161
                        obs.setValueComplex(extension + " image |" + assignedKey);
1✔
162

163
                        // Remove the ComlexData from the Obs
164
                        obs.setComplexData(null);
1✔
NEW
165
                } catch (IOException e) {
×
NEW
166
                        throw new UncheckedIOException(e);
×
167
                }
1✔
168
                
169
                return obs;
1✔
170
        }
171
        
172
}
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