Project

General

Profile

Download (15.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2007 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

    
10
package eu.etaxonomy.cdm.api.service;
11

    
12
import java.io.IOException;
13
import java.util.ArrayList;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19
import java.util.stream.Collectors;
20

    
21
import org.apache.http.HttpException;
22
import org.springframework.beans.factory.annotation.Autowired;
23
import org.springframework.stereotype.Service;
24
import org.springframework.transaction.annotation.Transactional;
25

    
26
import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
27
import eu.etaxonomy.cdm.api.service.config.MediaDeletionConfigurator;
28
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
29
import eu.etaxonomy.cdm.api.service.pager.Pager;
30
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
31
import eu.etaxonomy.cdm.common.media.ImageInfo;
32
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
33
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
34
import eu.etaxonomy.cdm.model.common.CdmBase;
35
import eu.etaxonomy.cdm.model.common.ICdmBase;
36
import eu.etaxonomy.cdm.model.description.DescriptionBase;
37
import eu.etaxonomy.cdm.model.description.IDescribable;
38
import eu.etaxonomy.cdm.model.description.MediaKey;
39
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
40
import eu.etaxonomy.cdm.model.description.TaxonDescription;
41
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
42
import eu.etaxonomy.cdm.model.description.TextData;
43
import eu.etaxonomy.cdm.model.location.NamedArea;
44
import eu.etaxonomy.cdm.model.media.Media;
45
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
46
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
47
import eu.etaxonomy.cdm.model.media.Rights;
48
import eu.etaxonomy.cdm.model.metadata.CdmPreference;
49
import eu.etaxonomy.cdm.model.metadata.PreferencePredicate;
50
import eu.etaxonomy.cdm.model.metadata.PreferenceSubject;
51
import eu.etaxonomy.cdm.model.name.TaxonName;
52
import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
53
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
54
import eu.etaxonomy.cdm.model.taxon.Taxon;
55
import eu.etaxonomy.cdm.persistence.dao.media.IMediaDao;
56
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
57

    
58
@Service
59
@Transactional(readOnly=true)
60
public class MediaServiceImpl extends IdentifiableServiceBase<Media,IMediaDao> implements IMediaService {
61

    
62
    public static final Integer IMAGE_READ_TIMEOUT = 3000;
63

    
64

    
65
    @Override
66
    @Autowired
67
	protected void setDao(IMediaDao dao) {
68
		this.dao = dao;
69
	}
70

    
71
	@Autowired
72
    private IOccurrenceService specimenService;
73
	@Autowired
74
    private ITaxonService taxonService;
75
	@Autowired
76
    private INameService nameService;
77
	@Autowired
78
	private IPreferenceService prefsService;
79

    
80

    
81
	@Override
82
    public Pager<MediaKey> getMediaKeys(Set<Taxon> taxonomicScope, Set<NamedArea> geoScopes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
83
        long numberOfResults = dao.countMediaKeys(taxonomicScope, geoScopes);
84

    
85
		List<MediaKey> results = new ArrayList<>();
86
		if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
87
			results = dao.getMediaKeys(taxonomicScope, geoScopes, pageSize, pageNumber, propertyPaths);
88
		}
89

    
90
		return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
91
	}
92

    
93
	@Override
94
    public Pager<Rights> getRights(Media t, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
95
        long numberOfResults = dao.countRights(t);
96

    
97
		List<Rights> results = new ArrayList<>();
98
		if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
99
			results = dao.getRights(t, pageSize, pageNumber,propertyPaths);
100
		}
101

    
102
		return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
103
	}
104

    
105
	@Override
106
	@Transactional(readOnly = false)
107
    public UpdateResult updateCaches(Class<? extends Media> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<Media> cacheStrategy, IProgressMonitor monitor) {
108
		if (clazz == null){
109
			clazz = Media.class;
110
		}
111
		return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
112
	}
113

    
114
    @Override
115
    @Transactional(readOnly=false)
116
    public DeleteResult delete(UUID mediaUuid, MediaDeletionConfigurator config) {
117
        DeleteResult result = new DeleteResult();
118
        Media media = this.load(mediaUuid);
119
        if (media == null){
120
            return result;
121
        }
122
        result = isDeletable(mediaUuid, config);
123
        if (result.isOk()){
124
            Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(media);
125
            for (CdmBase ref: references){
126

    
127
                IDescribable<?> updatedObject = null;
128
                IService<ICdmBase> service = null;
129
                if (ref instanceof TextData){
130

    
131
                    TextData textData = HibernateProxyHelper.deproxy(ref, TextData.class);
132
                    DescriptionBase<?> description = HibernateProxyHelper.deproxy(textData.getInDescription(), DescriptionBase.class);
133

    
134
                    IDescribable<?> objectToUpdate = null;
135
                    boolean deleteIsMatchingInstance = false;
136
                    if (description instanceof TaxonDescription){
137
                        objectToUpdate = ((TaxonDescription)description).getTaxon();
138
                        deleteIsMatchingInstance = config.getDeleteFrom() instanceof Taxon;
139
                        service = (IService)taxonService;
140
                    }else if (description instanceof SpecimenDescription){
141
                        objectToUpdate = ((SpecimenDescription)description).getDescribedSpecimenOrObservation();
142
                        deleteIsMatchingInstance = config.getDeleteFrom() instanceof SpecimenOrObservationBase;
143
                        service = (IService)specimenService;
144
                    }else if (description instanceof TaxonNameDescription){
145
                        objectToUpdate = ((TaxonNameDescription)description).getTaxonName();
146
                        deleteIsMatchingInstance = config.getDeleteFrom() instanceof TaxonName;
147
                        service = (IService)nameService;
148
                    }else{
149
                        throw new RuntimeException("Unsupported DescriptionBase class");
150
                    }
151

    
152
                    if (objectToUpdate == null ){
153
                        continue;
154
                    } else if ( (config.isDeleteFromDescription() && deleteIsMatchingInstance  &&
155
                                   config.getDeleteFrom().getId() == objectToUpdate.getId())
156
                                || config.isDeleteFromEveryWhere()){
157
                        updatedObject = handleDeleteMedia(media, textData, description,
158
                                (IDescribable)objectToUpdate);
159
                    } else {
160
                        // this should not be happen, because it is not deletable. see isDeletable
161
                        result.setAbort();
162
                    }
163

    
164
//                } else if (ref instanceof MediaSpecimen && config.getDeleteFrom().getId() == ref.getId() && config.getDeleteFrom() instanceof MediaSpecimen){
165
//                        MediaSpecimen mediaSpecimen = HibernateProxyHelper.deproxy(ref, MediaSpecimen.class);
166
//                        mediaSpecimen.setMediaSpecimen(null);
167
//                        updatedObject = mediaSpecimen;
168
//                        service = (IService)specimenService;
169
                }else if (ref instanceof MediaRepresentation){
170
                    continue;
171
                }else {
172
                    result.setAbort();
173
                }
174

    
175
                if (updatedObject != null){
176
                    service.update(updatedObject); //service should always be != null if updatedObject != null
177
                    result.addUpdatedObject((CdmBase)updatedObject);
178
                }
179
            }
180
            if (result.isOk()){
181
                dao.delete(media);
182
                result.addDeletedObject(media);
183
            }
184

    
185
        }
186
        return result;
187
    }
188

    
189
    /**
190
     * @param media
191
     * @param textData
192
     * @param desc
193
     * @param taxon
194
     */
195
    private IDescribable<DescriptionBase<?>> handleDeleteMedia(Media media, TextData textData,
196
            DescriptionBase<?> desc, IDescribable<DescriptionBase<?>> describable) {
197
        while(textData.getMedia().contains(media)){
198
            textData.removeMedia(media);
199
        }
200
        //if the textData contains text it should not be deleted
201
        if (textData.getMedia().isEmpty() && textData.getMultilanguageText().isEmpty()){
202
            desc.removeElement(textData);
203
        }
204
        if (desc.getElements().isEmpty()){
205
            describable.removeDescription(desc);
206
        }
207
        return describable;
208
    }
209

    
210

    
211
    @Override
212
    public DeleteResult isDeletable(UUID mediaUuid, DeleteConfiguratorBase config){
213
        DeleteResult result = new DeleteResult();
214
        Media media = this.load(mediaUuid);
215
        Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(media);
216
        MediaDeletionConfigurator mediaConfig = (MediaDeletionConfigurator)config;
217
        CdmBase deleteFrom = mediaConfig.getDeleteFrom();
218

    
219
        if (mediaConfig.isDeleteFromEveryWhere()){
220
           return result;
221
        }
222
        for (CdmBase ref: references){
223
            String message = null;
224
            if (ref instanceof MediaRepresentation){
225
                continue;
226
            }
227
            if (ref instanceof TextData){
228
                TextData textData = HibernateProxyHelper.deproxy(ref, TextData.class);
229
                DescriptionBase description = HibernateProxyHelper.deproxy(textData.getInDescription(), DescriptionBase.class);
230

    
231
                if (description instanceof TaxonDescription){
232
                    TaxonDescription desc = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
233
                    if (desc.getTaxon() == null || (mediaConfig.isDeleteFromDescription() && (deleteFrom instanceof Taxon && ((Taxon)deleteFrom).getId() == desc.getTaxon().getId()))){
234
                        continue;
235
                    } else{
236
                        message = "The media can't be deleted from the database because it is referenced by a taxon. ("+desc.getTaxon().getTitleCache()+")";
237
                        result.setAbort();
238
                    }
239

    
240
                } else if (description instanceof SpecimenDescription){
241
                    SpecimenDescription desc = HibernateProxyHelper.deproxy(description, SpecimenDescription.class);
242
                    if (desc.getDescribedSpecimenOrObservation() == null || (mediaConfig.isDeleteFromDescription() && (deleteFrom instanceof SpecimenOrObservationBase && ((SpecimenOrObservationBase)deleteFrom).getId() == desc.getDescribedSpecimenOrObservation().getId()))){
243
                        continue;
244
                    } else{
245
                        message = "The media can't be deleted from the database because it is referenced by a specimen or observation. ("+desc.getDescribedSpecimenOrObservation().getTitleCache()+")";
246
                        result.setAbort();
247
                    }
248
                } else if (description instanceof TaxonNameDescription){
249
                    TaxonNameDescription desc = HibernateProxyHelper.deproxy(description, TaxonNameDescription.class);
250
                    if (desc.getTaxonName() == null || (mediaConfig.isDeleteFromDescription() && (deleteFrom instanceof TaxonName && ((TaxonName)deleteFrom).getId() == desc.getTaxonName().getId()))){
251
                        continue;
252
                    } else{
253
                        message = "The media can't be deleted from the database because it is referenced by a scientific name. ("+desc.getTaxonName().getTitleCache()+")";
254
                        result.setAbort();
255
                    }
256
                }
257

    
258
            }if (ref instanceof MediaSpecimen){
259
               message = "The media can't be deleted from the database because it is referenced by a mediaspecimen. ("+((MediaSpecimen)ref).getTitleCache()+")";
260
               result.setAbort();
261
            }else {
262
                message = "The media can't be completely deleted because it is referenced by another " + ref.getUserFriendlyTypeName() ;
263
                result.setAbort();
264
            }
265
            if (message != null){
266
                result.addException(new ReferencedObjectUndeletableException(message));
267
                result.addRelatedObject(ref);
268

    
269
            }
270

    
271
        }
272

    
273
        return result;
274
    }
275

    
276
    /**
277
     * Reads the metadata as stored in the file or web resource and filters the data by the include and exclude lists of key names
278
     * as stored in the data base properties {@link PreferencePredicate#MediaMetadataKeynameExcludes} and {@link PreferencePredicate#MediaMetadataKeynameExcludes}
279
     * <p>
280
     * Metadata of multiple parts is merged into one common metadata map whereas the later part being read may overwrite data from previous parts.
281
     * The consequences of this can be neglected since we don't expect that multiple parts are actually being used.
282
     *
283
     * @param represenatation
284
     * @return
285
     * @throws IOException
286
     * @throws HttpException
287
     */
288
    public Map<String, String> readResourceMetadataFiltered(MediaRepresentation represenatation) throws IOException, HttpException {
289

    
290
        List<String> includes = mediaMetadataKeyIncludes();
291
        List<String> excludes = mediaMetadataKeyExludes();
292
        Map<String, String> metadata = new HashMap<>();
293

    
294
        for(MediaRepresentationPart part : represenatation.getParts()) {
295
            ImageInfo iInfo = ImageInfo.NewInstance(part.getUri(), IMAGE_READ_TIMEOUT);
296
            metadata.putAll(iInfo.getMetaData());
297
        }
298

    
299
        if(!includes.isEmpty()) {
300
            metadata = metadata.entrySet()
301
                    .stream()
302
                    .filter( e -> containsCaseInsensitive(e.getKey(), includes))
303
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
304
        }
305
        if(!excludes.isEmpty()) {
306
            metadata = metadata.entrySet()
307
                    .stream()
308
                    .filter( e -> !containsCaseInsensitive(e.getKey(), excludes))
309
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
310
        }
311

    
312
        if(metadata == null) {
313
            metadata = new HashMap<>(0);
314
        }
315
        return metadata;
316
    }
317

    
318
    private boolean containsCaseInsensitive(String s, List<String> l){
319
        return l.stream().anyMatch(x -> x.equalsIgnoreCase(s));
320
    }
321

    
322
    protected List<String> mediaMetadataKeyExludes(){
323
        CdmPreference pref = prefsService.find(CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), PreferencePredicate.MediaMetadataKeynameExcludes));
324
        return pref.splitStringListValue();
325
    }
326

    
327
    protected List<String> mediaMetadataKeyIncludes(){
328
        CdmPreference pref = prefsService.find(CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), PreferencePredicate.MediaMetadataKeynameIncludes));
329
        return pref.splitStringListValue();
330
    }
331

    
332

    
333
}
(72-72/100)