ref #10453: catch/log the error if makeNewMediaRepresentationsFor fails
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / util / MediaToolbox.java
1 /**
2 * Copyright (C) 2020 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.remote.controller.util;
10
11 import java.util.ArrayList;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import org.apache.logging.log4j.LogManager;
18 import org.apache.logging.log4j.Logger;
19 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.stereotype.Component;
21
22 import com.fasterxml.jackson.core.JsonProcessingException;
23 import com.fasterxml.jackson.databind.JsonMappingException;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.fasterxml.jackson.databind.type.CollectionType;
26
27 import eu.etaxonomy.cdm.api.service.IPreferenceService;
28 import eu.etaxonomy.cdm.api.service.media.DefaultMediaTransformations;
29 import eu.etaxonomy.cdm.api.service.media.MediaUriTransformation;
30 import eu.etaxonomy.cdm.api.service.media.MediaUriTransformationProcessor;
31 import eu.etaxonomy.cdm.model.media.Media;
32 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
33 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
34 import eu.etaxonomy.cdm.model.media.MediaUtils;
35 import eu.etaxonomy.cdm.model.media.MediaUtils.MissingValueStrategy;
36 import eu.etaxonomy.cdm.model.metadata.CdmPreference;
37 import eu.etaxonomy.cdm.model.metadata.CdmPreference.PrefKey;
38 import eu.etaxonomy.cdm.model.metadata.PreferencePredicate;
39 import eu.etaxonomy.cdm.model.metadata.PreferenceSubject;
40
41 /**
42 * Utility service which creates volatile objects which must not be persisted.
43 * <p>
44 * By now this class provides methods for filtering {@link Media} and {@link MediaRepresentation}s
45 * <p>
46 * See also {@link MediaUriTransformationProcessor} and {@link MediaUriTransformation}
47 *
48 * @author a.kohlbecker
49 * @since Jul 8, 2020
50 */
51 @Component // not used for component scan, see eu.etaxonomy.cdm.remote.config.CdmRemoteConfiguration
52 public class MediaToolbox implements IMediaToolbox {
53
54 private static final Logger logger = LogManager.getLogger();
55
56 private List<MediaUriTransformation> transformations = null;
57
58 private Integer mediaRepresentationTransformationsLastHash = null;
59
60 @Autowired
61 private IPreferenceService preferenceService;
62
63 @Override
64 public List<Media> processAndFilterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, String[] mimeTypes,
65 Integer widthOrDuration, Integer height, Integer size, List<Media> mediaList) {
66
67 MediaUriTransformationProcessor mediaTransformationProcessor = new MediaUriTransformationProcessor();
68 mediaTransformationProcessor.addAll(readTransformations());
69
70 for(Media media : mediaList) {
71 List<MediaRepresentation> newReprs = new ArrayList<>();
72 for(MediaRepresentation repr : media.getRepresentations()) {
73 for(MediaRepresentationPart part : repr.getParts()) {
74 try {
75 newReprs.addAll(mediaTransformationProcessor.makeNewMediaRepresentationsFor(part));
76 }catch(Exception e) {
77 logger.error(e.getLocalizedMessage(), e);
78 }
79 }
80 }
81 for(MediaRepresentation r : newReprs) {
82 media.addRepresentation(r);
83 }
84 media.setId(0); // prevent from persisting the modified media entity accidentally
85 }
86 return filterPreferredMediaRepresentations(mediaList, type, mimeTypes, widthOrDuration, height, size);
87 }
88
89 @Override
90 public MediaRepresentation processAndFindBestMatchingRepresentation(Media media,
91 Class<? extends MediaRepresentationPart> type, Integer size, Integer height, Integer widthOrDuration,
92 String[] mimeTypes, MissingValueStrategy missingValStrategy) {
93
94 MediaUriTransformationProcessor mediaTransformationProcessor = new MediaUriTransformationProcessor();
95 mediaTransformationProcessor.addAll(readTransformations());
96
97 Set<MediaRepresentation> newReprs = new HashSet<>();
98 for (MediaRepresentation repr : media.getRepresentations()) {
99 for (MediaRepresentationPart part : repr.getParts()) {
100 newReprs.addAll(mediaTransformationProcessor.makeNewMediaRepresentationsFor(part));
101 }
102 }
103 newReprs.addAll(media.getRepresentations());
104 return MediaUtils.findBestMatchingRepresentation(newReprs, type, size, height, widthOrDuration, mimeTypes, missingValStrategy);
105 }
106
107 /**
108 * @deprecated needs to be replaced, see https://dev.e-taxonomy.eu/redmine/issues/9160
109 */
110 @Override
111 @Deprecated
112 public List<Media> filterPreferredMediaRepresentations(List<Media> mediaList, Class<? extends MediaRepresentationPart> type,
113 String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size) {
114
115 Map<Media, MediaRepresentation> mediaRepresentationMap = MediaUtils.findPreferredMedia(mediaList, type, mimeTypes, widthOrDuration, height, size, MediaUtils.MissingValueStrategy.MAX);
116
117 List<Media> filteredMedia = new ArrayList<>(mediaRepresentationMap.size());
118 for (Media media : mediaRepresentationMap.keySet()) {
119 media.getRepresentations().clear();
120 media.addRepresentation(mediaRepresentationMap.get(media));
121 media.setId(0); // prevent from persisting the modified media entity accidentally
122 filteredMedia.add(media);
123 }
124 return filteredMedia;
125 }
126
127 /**
128 * Read the {@link MediaUriTransformation MediaUriTransformations} from the cdm preferences ({@link PreferencePredicate.MediaRepresentationTransformations}
129 * or use the default defined in {@link DefaultMediaTransformations#digilib()}
130 *
131 */
132 private List<MediaUriTransformation> readTransformations() {
133
134 PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), PreferencePredicate.MediaRepresentationTransformations);
135 CdmPreference pref = preferenceService.find(key);
136 if(pref != null && pref.getValue() != null) {
137 if(mediaRepresentationTransformationsLastHash == null || mediaRepresentationTransformationsLastHash != pref.getValue().hashCode()) {
138 // loaded value is different from last value
139 ObjectMapper mapper = new ObjectMapper();
140 CollectionType javaType = mapper.getTypeFactory()
141 .constructCollectionType(List.class, MediaUriTransformation.class);
142 try {
143 transformations = mapper.readValue(pref.getValue(), javaType);
144 mediaRepresentationTransformationsLastHash = pref.getValue().hashCode();
145 } catch (JsonMappingException e) {
146 logger.error(e);
147 } catch (JsonProcessingException e) {
148 logger.error(e);
149 }
150 }
151 }
152 if(transformations == null) {
153 transformations = DefaultMediaTransformations.digilib();
154 }
155
156 return transformations;
157 }
158
159 /**
160 * @param trans the list of MediaUriTransformation to be serialized
161 * @return the JSON string
162 * @throws JsonProcessingException
163 */
164 static protected String transformationsToJson(List<MediaUriTransformation> trans) throws JsonProcessingException {
165
166 ObjectMapper mapper = new ObjectMapper();
167 CollectionType javaType = mapper.getTypeFactory()
168 .constructCollectionType(List.class, MediaUriTransformation.class);
169
170 String json = mapper.writerFor(javaType).withDefaultPrettyPrinter().writeValueAsString(trans);
171 return json;
172 }
173
174 /**
175 *
176 * @param args
177 * @throws JsonProcessingException
178 */
179 public static void main(String[] args) throws JsonProcessingException {
180
181 System.out.println("Default tansformations for digilib");
182 System.out.println("========================================");
183 System.out.println(transformationsToJson(DefaultMediaTransformations.digilib()));
184 }
185
186 }