Project

General

Profile

Revision 8165e2b9

ID8165e2b988fc9f01431fdb81c414308fbfa11c25
Parent 20de2ce5
Child 5ccd238c

Added by Andreas Kohlbecker 6 months ago

ref #9134 no longer storing DefaultMediaTransformations in the db, better exception handling and more documentation

View differences:

cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/iiif/ManifestController.java
159 159
        return iiifMapper.writeValueAsString(manifest);
160 160
    }
161 161

  
162
    private <T extends IdentifiableEntity> Manifest manifestFor(EntityMediaContext<T> entityMediaContext, String onEntitiyType, String onEntityUuid) {
162
    private <T extends IdentifiableEntity> Manifest manifestFor(EntityMediaContext<T> entityMediaContext, String onEntitiyType, String onEntityUuid) throws IOException {
163 163

  
164 164
        List<Canvas> canvases = new ArrayList<>(entityMediaContext.getMedia().size());
165 165

  
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/util/IMediaToolbox.java
8 8
*/
9 9
package eu.etaxonomy.cdm.remote.controller.util;
10 10

  
11
import java.io.IOException;
11 12
import java.util.List;
12 13

  
13 14
import eu.etaxonomy.cdm.model.media.Media;
......
21 22
 */
22 23
public interface IMediaToolbox {
23 24

  
25
    /**
26
     * Extend the set of media representations in <code>media</code>, filter the resulting representations by the
27
     * attributes defined via the parameters <code>type</code>, <code>size</code>, <code>height</code>, <code>widthOrDuration</code>
28
     * and <code>mimeTypes</code> and finally return the list of matching MediaRepresentations ordered by the ranging of the match.
29
     *
30
     */
24 31
    List<Media> processAndFilterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type,
25
            String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size, List<Media> taxonGalleryMedia);
32
            String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size, List<Media> taxonGalleryMedia) throws IOException;
26 33

  
27
    List<Media> filterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, String[] mimeTypes,
28
            Integer widthOrDuration, Integer height, Integer size, List<Media> taxonGalleryMedia);
34
    /**
35
     * Filters the Media  objects and the contained MediaRepresentations the by the
36
     * attributes defined via the parameters <code>type</code>, <code>size</code>, <code>height</code>, <code>widthOrDuration</code>
37
     * and <code>mimeTypes</code> and finally return the media objects which have at lease one matching representation.
38
     * The MediaRepresentations are also filtered and ordered by the ranging of the match.
39
     */
40
    List<Media> filterPreferredMediaRepresentations(List<Media> mediaList, Class<? extends MediaRepresentationPart> type,
41
            String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size);
29 42

  
43
    /**
44
     * Extend the set of media representations in <code>media</code>, filter the resulting representations by the
45
     * attributes defined via the parameters <code>type</code>, <code>size</code>, <code>height</code>, <code>widthOrDuration</code>
46
     * and <code>mimeTypes</code> and finally return the best matching MediaRepresentation.
47
     *
48
     * @param media
49
     * @param type
50
     * @param size
51
     * @param height
52
     * @param widthOrDuration
53
     * @param mimeTypes
54
     * @param missingValStrategy Strategies for replacing <code>null</code> values with a numeric value.
55
     * @return
56
     * @throws IOException
57
     */
30 58
    MediaRepresentation processAndFindBestMatchingRepresentation(Media media,
31 59
            Class<? extends MediaRepresentationPart> type, Integer size, Integer height, Integer widthOrDuration,
32
            String[] mimeTypes, MissingValueStrategy missingValStrategy);
60
            String[] mimeTypes, MissingValueStrategy missingValStrategy) throws IOException;
33 61

  
34 62
}
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/util/MediaToolbox.java
14 14

  
15 15
import org.apache.log4j.Logger;
16 16
import org.springframework.beans.factory.annotation.Autowired;
17
import org.springframework.stereotype.Component;
17 18

  
18 19
import com.fasterxml.jackson.core.JsonProcessingException;
19 20
import com.fasterxml.jackson.databind.JsonMappingException;
......
21 22
import com.fasterxml.jackson.databind.type.CollectionType;
22 23

  
23 24
import eu.etaxonomy.cdm.api.service.IPreferenceService;
25
import eu.etaxonomy.cdm.api.service.media.DefaultMediaTransformations;
24 26
import eu.etaxonomy.cdm.api.service.media.MediaUriTransformation;
25 27
import eu.etaxonomy.cdm.api.service.media.MediaUriTransformationProcessor;
26
import eu.etaxonomy.cdm.api.service.media.SearchReplace;
27 28
import eu.etaxonomy.cdm.model.media.Media;
28 29
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
29 30
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
......
35 36
import eu.etaxonomy.cdm.model.metadata.PreferenceSubject;
36 37

  
37 38
/**
38
 * See {@link MediaUriTransformationProcessor} and {@link MediaUriTransformation}
39
 * Utility service which which creates volatile object which must not be persisted.
40
 * <p>
41
 * By now this class provides methods for filtering {@link Media} and  {@link MediaRepresentation}s
42
 * <p>
43
 * See also {@link MediaUriTransformationProcessor} and {@link MediaUriTransformation}
39 44
 *
40 45
 * @author a.kohlbecker
41 46
 * @since Jul 8, 2020
42 47
 */
48
@Component // not used for component scan, see eu.etaxonomy.cdm.remote.config.CdmRemoteConfiguration
43 49
public class MediaToolbox implements IMediaToolbox {
44 50

  
45
    private static final String SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET = "mediaRepresentationTransformationsReset";
46

  
47 51
    private static final Logger logger = Logger.getLogger(MediaToolbox.class);
48 52

  
49 53
    private List<MediaUriTransformation> transformations = null;
......
55 59

  
56 60
    @Override
57 61
    public List<Media> processAndFilterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, String[] mimeTypes,
58
            Integer widthOrDuration, Integer height, Integer size, List<Media> galleryMedia) {
62
            Integer widthOrDuration, Integer height, Integer size, List<Media> mediaList) {
59 63

  
60 64
        MediaUriTransformationProcessor mediaTransformationProcessor = new MediaUriTransformationProcessor();
61 65
        mediaTransformationProcessor.addAll(readTransformations());
62 66

  
63
        for(Media media : galleryMedia) {
67
        for(Media media : mediaList) {
64 68
            List<MediaRepresentation> newRepr = new ArrayList<>();
65 69
            for(MediaRepresentation repr : media.getRepresentations()) {
66 70
                for(MediaRepresentationPart part : repr.getParts()) {
......
69 73
            }
70 74
            media.getRepresentations().addAll(newRepr);
71 75
        }
72
        return filterPreferredMediaRepresentations(type, mimeTypes, widthOrDuration, height, size, galleryMedia);
76
        return filterPreferredMediaRepresentations(mediaList, type, mimeTypes, widthOrDuration, height, size);
73 77
    }
74 78

  
75 79
    @Override
......
90 94

  
91 95
        return MediaUtils.findBestMatchingRepresentation(media, type, size, height, widthOrDuration, mimeTypes,
92 96
                missingValStrategy);
93

  
94 97
    }
95 98

  
96 99
    @Override
97
    public List<Media> filterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, String[] mimeTypes,
98
            Integer widthOrDuration, Integer height, Integer size, List<Media> galleryMedia) {
100
    public List<Media> filterPreferredMediaRepresentations(List<Media> mediaList, Class<? extends MediaRepresentationPart> type,
101
            String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size) {
102

  
99 103

  
100
        Map<Media, MediaRepresentation> mediaRepresentationMap = MediaUtils.findPreferredMedia(
101
                galleryMedia, type, mimeTypes, widthOrDuration, height, size, MediaUtils.MissingValueStrategy.MAX);
104
        Map<Media, MediaRepresentation> mediaRepresentationMap = MediaUtils.findPreferredMedia(mediaList, type, mimeTypes, widthOrDuration, height, size, MediaUtils.MissingValueStrategy.MAX);
102 105

  
103 106
        List<Media> filteredMedia = new ArrayList<>(mediaRepresentationMap.size());
104 107
        for (Media media : mediaRepresentationMap.keySet()) {
......
109 112
        return filteredMedia;
110 113
    }
111 114

  
115
    /**
116
     * Read the {@link MediaUriTransformation MediaUriTransformations} from the cdm preferences ({@link PreferencePredicate.MediaRepresentationTransformations}
117
     * or use the default defined in {@link DefaultMediaTransformations#digilib()}
118
     *
119
     */
112 120
    private List<MediaUriTransformation> readTransformations() {
113 121

  
114
        //System.setProperty(SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET, "1");
115 122
        PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), PreferencePredicate.MediaRepresentationTransformations);
116 123
        CdmPreference pref = preferenceService.find(key);
117 124
        if(pref != null && pref.getValue() != null) {
118
            if(System.getProperty(SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET) == null
119
                    || mediaRepresentationTransformationsLastHash == null
120
                    || mediaRepresentationTransformationsLastHash != pref.getValue().hashCode()) {
125
            if(mediaRepresentationTransformationsLastHash == null || mediaRepresentationTransformationsLastHash != pref.getValue().hashCode()) {
121 126
                // loaded value is different from last value
122 127
                ObjectMapper mapper = new ObjectMapper();
123 128
                CollectionType javaType = mapper.getTypeFactory()
......
132 137
                }
133 138
            }
134 139
        }
135
        if(transformations == null || System.getProperty(SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET) != null) {
136

  
137
            transformations = new ArrayList<>();
138
            MediaUriTransformation tr1 = new MediaUriTransformation();
139

  
140
            tr1.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!200,200/0/default.jpg"));
141
            tr1.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
142
            tr1.setMimeType("image/jpeg");
143
            tr1.setWidth(200);
144
            tr1.setHeight(200);
145

  
146
            MediaUriTransformation tr2 = new MediaUriTransformation();
147

  
148
            tr2.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!400,400/0/default.jpg"));
149
            tr2.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
150
            tr2.setMimeType("image/jpeg");
151
            tr2.setWidth(400);
152
            tr2.setHeight(400);
153

  
154

  
155
            MediaUriTransformation tr3 = new MediaUriTransformation();
156
            tr3.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!400,400/0/default.jpg"));
157
            tr3.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
158
            tr3.setMimeType("image/jpeg");
159
            tr3.setWidth(400);
160
            tr3.setHeight(400);
161

  
162
            MediaUriTransformation tr4 = new MediaUriTransformation();
163
            tr4.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!200,200/0/default.jpg"));
164
            tr4.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
165
            tr4.setMimeType("image/jpeg");
166
            tr4.setWidth(200);
167
            tr4.setHeight(200);
168

  
169
            transformations.add(tr1);
170
            transformations.add(tr2);
171
            transformations.add(tr3);
172
            transformations.add(tr4);
173

  
174
            ObjectMapper mapper = new ObjectMapper();
175
            CollectionType javaType = mapper.getTypeFactory()
176
                    .constructCollectionType(List.class, MediaUriTransformation.class);
177
            try {
178
                String json = mapper.writerFor(javaType).writeValueAsString(transformations);
179
                pref = CdmPreference.NewDatabaseInstance(PreferencePredicate.MediaRepresentationTransformations, json);
180
                preferenceService.set(pref);
181
            } catch (JsonProcessingException e) {
182
                logger.error(e);
183
            }
140
        if(transformations == null) {
141
            transformations = DefaultMediaTransformations.digilib();
184 142
        }
185 143

  
186 144
        return transformations;
187 145
    }
146

  
147
    /**
148
     * @param trans the list of MediaUriTransformation to be serialized
149
     * @return the JSON string
150
     * @throws JsonProcessingException
151
     */
152
    static protected String transformationsToJson(List<MediaUriTransformation> trans) throws JsonProcessingException {
153

  
154
      ObjectMapper mapper = new ObjectMapper();
155
      CollectionType javaType = mapper.getTypeFactory()
156
              .constructCollectionType(List.class, MediaUriTransformation.class);
157

  
158
      String json = mapper.writerFor(javaType).withDefaultPrettyPrinter().writeValueAsString(trans);
159
      return json;
160
    }
161

  
162
    /**
163
     *
164
     * @param args
165
     * @throws JsonProcessingException
166
     */
167
    public static void main(String[] args) throws JsonProcessingException {
168

  
169
        System.out.println("Default tansformations for digilib");
170
        System.out.println("========================================");
171
        System.out.println(transformationsToJson(DefaultMediaTransformations.digilib()));
172
    }
173

  
188 174
}
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/media/DefaultMediaTransformations.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.api.service.media;
10

  
11
import java.util.ArrayList;
12
import java.util.List;
13

  
14
/**
15
 * Factory class to create default transformations
16
 *
17
 * @author a.kohlbecker
18
 * @since Jul 15, 2020
19
 */
20
public class DefaultMediaTransformations {
21

  
22
    /**
23
     * Create default transformations for the diglilib server:
24
     * <p>
25
     * Links:
26
     * <ul>
27
     * <li>https://robcast.github.io/digilib/scaler-api.html</li>
28
     * <li>https://robcast.github.io/digilib/iiif-api.html</li>
29
     * </ul>
30
     *
31
     * @return
32
     */
33
    static public List<MediaUriTransformation> digilib() {
34

  
35
        List<MediaUriTransformation> defaultTransformations = new ArrayList<>();
36

  
37
        /*
38
         * dataPortalPreviewImage:
39
         * image which fits the default preview image size which is
40
         * for example used in the taxon general page, max extend of the resulting images is 400px
41
         */
42
        String dataPortalPreviewImage = "digilib/Scaler/IIIF/$1!$2/full/!400,400/0/default.jpg";
43

  
44
        /*
45
         * universalViewerThumbnail:
46
         * crop to fit into a 200 x 147 preview box, the uvfix=1 parameter is used to
47
         * prevent the universal viewer from corrupting the last query parameter. UV appends a parameter t with
48
         * question mark character which causes problems for the URI query parser see https://dev.e-taxonomy.eu/redmine/issues/9132#note-8
49
         */
50
        String universalViewerThumbnail = "digilib/Scaler/?fn=$1/$2&mo=crop&dw=200&dh=147&uvfix=1";
51

  
52
        MediaUriTransformation tr1 = new MediaUriTransformation();
53
        tr1.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", dataPortalPreviewImage));
54
        tr1.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
55
        tr1.setMimeType("image/jpeg");
56
        tr1.setWidth(400);
57
        tr1.setHeight(400);
58

  
59
        MediaUriTransformation tr2 = new MediaUriTransformation();
60
        tr2.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", universalViewerThumbnail));
61
        tr2.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
62
        tr2.setMimeType("image/jpeg");
63
        tr2.setWidth(200);
64
        tr2.setHeight(200);
65

  
66
        MediaUriTransformation tr3 = new MediaUriTransformation();
67
        tr3.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", dataPortalPreviewImage));
68
        tr3.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
69
        tr3.setMimeType("image/jpeg");
70
        tr3.setWidth(400);
71
        tr3.setHeight(400);
72

  
73
        MediaUriTransformation tr4 = new MediaUriTransformation();
74
        tr4.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", universalViewerThumbnail));
75
        tr4.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace!
76
        tr4.setMimeType("image/jpeg");
77
        tr4.setWidth(200);
78
        tr4.setHeight(200);
79

  
80
        defaultTransformations.add(tr2);
81
        defaultTransformations.add(tr1);
82
        defaultTransformations.add(tr3);
83
        defaultTransformations.add(tr4);
84

  
85
        return defaultTransformations;
86
    }
87

  
88

  
89

  
90
}

Also available in: Unified diff

Add picture from clipboard (Maximum size: 40 MB)