ref #10322 remove empty sources from singleSourced entities
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / portal / TaxonPageDtoLoaderBase.java
1 /**
2 * Copyright (C) 2024 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.portal;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.UUID;
15 import java.util.stream.Collectors;
16
17 import org.apache.commons.lang3.StringUtils;
18
19 import eu.etaxonomy.cdm.api.application.ICdmRepository;
20 import eu.etaxonomy.cdm.api.dto.portal.AnnotatableDto;
21 import eu.etaxonomy.cdm.api.dto.portal.AnnotationDto;
22 import eu.etaxonomy.cdm.api.dto.portal.CdmBaseDto;
23 import eu.etaxonomy.cdm.api.dto.portal.ContainerDto;
24 import eu.etaxonomy.cdm.api.dto.portal.MarkerDto;
25 import eu.etaxonomy.cdm.api.dto.portal.MediaDto2;
26 import eu.etaxonomy.cdm.api.dto.portal.SingleSourcedDto;
27 import eu.etaxonomy.cdm.api.dto.portal.SourceDto;
28 import eu.etaxonomy.cdm.api.dto.portal.SourcedDto;
29 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto;
30 import eu.etaxonomy.cdm.api.dto.portal.TaxonPageDto.MediaRepresentationDTO;
31 import eu.etaxonomy.cdm.api.dto.portal.config.IAnnotatableLoaderConfiguration;
32 import eu.etaxonomy.cdm.format.common.TypedLabel;
33 import eu.etaxonomy.cdm.format.reference.OriginalSourceFormatter;
34 import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
35 import eu.etaxonomy.cdm.model.common.Annotation;
36 import eu.etaxonomy.cdm.model.common.AnnotationType;
37 import eu.etaxonomy.cdm.model.common.CdmBase;
38 import eu.etaxonomy.cdm.model.common.ICdmBase;
39 import eu.etaxonomy.cdm.model.common.IPublishable;
40 import eu.etaxonomy.cdm.model.common.Language;
41 import eu.etaxonomy.cdm.model.common.LanguageString;
42 import eu.etaxonomy.cdm.model.common.Marker;
43 import eu.etaxonomy.cdm.model.common.MultilanguageTextHelper;
44 import eu.etaxonomy.cdm.model.common.SingleSourcedEntityBase;
45 import eu.etaxonomy.cdm.model.description.DescriptionBase;
46 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
47 import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
48 import eu.etaxonomy.cdm.model.media.ExternalLink;
49 import eu.etaxonomy.cdm.model.media.ImageFile;
50 import eu.etaxonomy.cdm.model.media.Media;
51 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
52 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
53 import eu.etaxonomy.cdm.model.name.TaxonName;
54 import eu.etaxonomy.cdm.model.reference.ISourceable;
55 import eu.etaxonomy.cdm.model.reference.NamedSource;
56 import eu.etaxonomy.cdm.model.reference.NamedSourceBase;
57 import eu.etaxonomy.cdm.model.reference.OriginalSourceBase;
58 import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
59 import eu.etaxonomy.cdm.model.reference.Reference;
60 import eu.etaxonomy.cdm.model.term.Representation;
61 import eu.etaxonomy.cdm.model.term.TermBase;
62 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
63 import eu.etaxonomy.cdm.strategy.cache.TaggedText;
64
65 /**
66 * @author muellera
67 * @since 27.02.2024
68 */
69 public abstract class TaxonPageDtoLoaderBase {
70
71 protected ICdmRepository repository;
72 protected ICdmGenericDao dao;
73
74 public TaxonPageDtoLoaderBase(ICdmRepository repository, ICdmGenericDao dao) {
75 this.repository = repository;
76 this.dao = dao;
77 }
78
79 //currently only used by fact loader
80 protected String getTermLabel(TermBase term, Language localeLang) {
81 if (term == null) {
82 return null;
83 }
84 Representation rep = term.getPreferredRepresentation(localeLang);
85 String label = rep == null ? null : rep.getLabel();
86 label = label == null ? term.getLabel() : label;
87 return label;
88 }
89
90 protected <P extends IPublishable> List<P> filterPublished(List<P> listToPublish) {
91 if (listToPublish == null) {
92 return null;
93 }else {
94 return listToPublish.stream().filter(s->s.isPublish()).collect(Collectors.toList());
95 }
96 }
97
98 protected <P extends IPublishable> Set<P> filterPublished(Set<P> setToPublish) {
99 if (setToPublish == null) {
100 return null;
101 }else {
102 return setToPublish.stream().filter(s->s.isPublish()).collect(Collectors.toSet());
103 }
104 }
105
106 public static void loadBaseData(IAnnotatableLoaderConfiguration config, CdmBase cdmBase, CdmBaseDto dto) {
107 dto.setId(cdmBase.getId());
108 dto.setUuid(cdmBase.getUuid());
109
110 loadAnnotatable(config, cdmBase, dto);
111 loadSources(config, cdmBase, dto);
112 //loadIdentifiable(cdmBase, dto);
113 }
114
115 static void loadAnnotatable(IAnnotatableLoaderConfiguration config, CdmBase cdmBase, CdmBaseDto dto) {
116 if (dto instanceof AnnotatableDto && cdmBase.isInstanceOf(AnnotatableEntity.class)) {
117 AnnotatableEntity annotatable = CdmBase.deproxy(cdmBase, AnnotatableEntity.class);
118 AnnotatableDto annotatableDto = (AnnotatableDto)dto;
119 //annotation
120 for (Annotation annotation : annotatable.getAnnotations()) {
121 if ((annotation.getAnnotationType() != null
122 //config == null currently needs to be allowed as it is also used by DistributionInfoBuilder an
123 //also for now empty annotation types needs to be interpreted as "no filter" as we do not distinguish
124 //null and empty yet, this may change in future
125 && (config == null || config.getAnnotationTypes().isEmpty()
126 || config.getAnnotationTypes().contains(annotation.getAnnotationType().getUuid())))
127 || (annotation.getAnnotationType() == null && config != null && config.getAnnotationTypes().contains(AnnotationType.uuidUntyped))
128 && StringUtils.isNotBlank(annotation.getText())) {
129
130 AnnotationDto annotationDto = new AnnotationDto();
131 annotatableDto.addAnnotation(annotationDto);
132 //TODO id needed? but need to adapt dto and container then
133 loadBaseData(config, annotation, annotationDto);
134 annotationDto.setText(annotation.getText());
135 UUID uuidAnnotationType = annotation.getAnnotationType() == null ? null :annotation.getAnnotationType().getUuid();
136 annotationDto.setTypeUuid(uuidAnnotationType);
137 //language etc. currently not yet used
138 }else if (config != null && !config.getAnnotationTypes().isEmpty() && config.getAnnotationTypes().contains(AnnotationType.uuidUntyped) && (annotation.getAnnotationType() == null)){
139 AnnotationDto annotationDto = new AnnotationDto();
140 annotatableDto.addAnnotation(annotationDto);
141 //TODO id needed? but need to adapt dto and container then
142 loadBaseData(config, annotation, annotationDto);
143 annotationDto.setText(annotation.getText());
144 UUID uuidAnnotationType = null;
145 annotationDto.setTypeUuid(uuidAnnotationType);
146
147 }
148 }
149
150 //marker
151 for (Marker marker : annotatable.getMarkers()) {
152 if (marker.getMarkerType() != null
153 //TODO markertype filter
154 // && marker.getMarkerType().getUuid().equals(AnnotationType.uuidEditorial)
155 ){
156
157 MarkerDto markerDto = new MarkerDto();
158 annotatableDto.addMarker(markerDto);
159 //TODO id needed? but need to adapt dto and container then
160 loadBaseData(config, marker, markerDto);
161 if (marker.getMarkerType() != null) {
162 markerDto.setTypeUuid(marker.getMarkerType().getUuid());
163 //TODO locale
164 markerDto.setType(marker.getMarkerType().getTitleCache());
165 }
166 markerDto.setValue(marker.getValue());
167 }
168 }
169 }
170 }
171
172 static void loadSources(IAnnotatableLoaderConfiguration config, CdmBase cdmBase, CdmBaseDto dto) {
173 if (dto instanceof SingleSourcedDto && cdmBase.isInstanceOf(SingleSourcedEntityBase.class)) {
174 //TODO other sourced
175 SingleSourcedEntityBase sourced = CdmBase.deproxy(cdmBase, SingleSourcedEntityBase.class);
176 SingleSourcedDto sourcedDto = (SingleSourcedDto)dto;
177 NamedSource source = sourced.getSource();
178 if (source != null && isPublicSource(source) && !source.checkEmpty()) {
179 SourceDto sourceDto = makeSource(config, source);
180 sourcedDto.setSource(sourceDto);
181 }
182 } else if (dto instanceof SourcedDto && cdmBase instanceof ISourceable) {
183 @SuppressWarnings("unchecked")
184 ISourceable<OriginalSourceBase> sourced = (ISourceable<OriginalSourceBase>)cdmBase;
185 SourcedDto sourcedDto = (SourcedDto)dto;
186 for (OriginalSourceBase source : sourced.getSources()) {
187 if (isPublicSource(source)) {
188 SourceDto sourceDto = makeSource(config, source);
189 sourcedDto.addSource(sourceDto);
190 }
191 }
192 }
193 //load description sources for facts
194 if (cdmBase.isInstanceOf(DescriptionElementBase.class)){
195 DescriptionBase<?> db = CdmBase.deproxy(cdmBase, DescriptionElementBase.class).getInDescription();
196 if (db != null) { //test sometime do not have a description for facts
197 SourcedDto sourcedDto = (SourcedDto)dto;
198 for (OriginalSourceBase source : db.getSources()) {
199 if (isPublicSource(source)) {
200 SourceDto sourceDto = new SourceDto();
201 loadSource(config, source, sourceDto);
202 sourcedDto.addSource(sourceDto);
203 }
204 }
205 }
206 }
207 }
208
209 private static void loadSource(IAnnotatableLoaderConfiguration config, OriginalSourceBase source, SourceDto sourceDto) {
210
211 source = CdmBase.deproxy(source);
212 //base data
213 loadBaseData(config, source, sourceDto);
214
215 ICdmBase linkedObject = source.getCitation();
216 if (linkedObject == null) {
217 //cdmsource
218 linkedObject = source.getCdmSource();
219 }
220
221 //citation doi & uri & links
222 Reference ref = source.getCitation();
223 if (ref != null) {
224 sourceDto.setDoi(ref.getDoiString());
225 sourceDto.setUri(ref.getUri());
226 sourceDto.setUuid(ref.getUuid());
227 sourceDto.setOriginalInfo(source.getOriginalInfo());
228 Set<ExternalLink> links = ref.getLinks();
229
230 if(source.getAccessed() != null) {
231 sourceDto.setAccessed(source.getAccessed().toString());
232 }
233 for (ExternalLink link : links) {
234 if (link.getUri() != null) {
235 sourceDto.addLink(link.getUri());
236 }
237 }
238 }
239
240 //label
241 //TODO this probably does not use specimen or cdmSource if necessary,
242 // also long citation is still preliminary
243 String label = OriginalSourceFormatter.INSTANCE_LONG_CITATION.format(source);
244 TypedLabel typedLabel = new TypedLabel(source, label);
245 sourceDto.addLabel(typedLabel);
246 sourceDto.setType(source.getType() != null ? source.getType().toString() : null);
247
248 if (source.isInstanceOf(NamedSourceBase.class)) {
249 NamedSourceBase ns = CdmBase.deproxy(source, NamedSourceBase.class);
250
251 //nameUsedInSource
252 TaxonName name = ns.getNameUsedInSource();
253 if (name != null) {
254 List<TaggedText> taggedName = name.cacheStrategy().getTaggedTitle(name);
255 //TODO nom status?
256 sourceDto.setNameInSource(taggedName);
257 sourceDto.setNameInSourceUuid(name.getUuid());
258 }
259
260 //specimen uuid
261 if (source.isInstanceOf(DescriptionElementSource.class)) {
262 DescriptionElementSource des = CdmBase.deproxy(source, DescriptionElementSource.class);
263 if (linkedObject == null) {
264 linkedObject = des.getSpecimen();
265 }
266 }
267 }
268
269 sourceDto.setLinkedUuid(getUuid(linkedObject));
270 String linkedObjectStr = linkedObject == null ? null : CdmBase.deproxy(linkedObject).getClass().getSimpleName();
271 sourceDto.setLinkedClass(linkedObjectStr);
272 }
273
274 protected static SourceDto makeSource(IAnnotatableLoaderConfiguration config, OriginalSourceBase source) {
275 if (source == null) {
276 return null;
277 }
278 SourceDto sourceDto = new SourceDto();
279 loadSource(config, source, sourceDto);
280 return sourceDto;
281 }
282
283 protected static UUID getUuid(ICdmBase cdmBase) {
284 return cdmBase == null ? null : cdmBase.getUuid();
285 }
286
287 protected static boolean isPublicSource(OriginalSourceBase source) {
288 if (source.getType() == null) {
289 return false; //should not happen
290 }else {
291 OriginalSourceType type = source.getType();
292 //TODO 3 make source type configurable
293 return type.isPublicSource();
294 }
295 }
296
297 protected void makeMediaContainer(IAnnotatableLoaderConfiguration config, TaxonPageDto result, List<Media> medias) {
298 ContainerDto<MediaDto2> container = new ContainerDto<>();
299
300 for (Media media : medias) {
301 handleSingleMedia(config, container, media);
302 }
303
304 if (container.getCount() > 0) {
305 result.setMedia(container);
306 }
307 }
308
309 protected void handleSingleMedia(IAnnotatableLoaderConfiguration config, ContainerDto<MediaDto2> container, Media media) {
310
311 MediaDto2 dto = new MediaDto2();
312 loadBaseData(config, media, dto);
313
314 //media
315 dto.setLabel(media.getTitleCache());
316 //TODO i18n
317 List<Language> languages = new ArrayList<>();
318 LanguageString description = MultilanguageTextHelper.getPreferredLanguageString(media.getAllDescriptions(), languages);
319 dto.setDescription(description == null ? null : description.getText());
320
321 //representations
322 ContainerDto<MediaRepresentationDTO> representations = new ContainerDto<>();
323 for (MediaRepresentation rep : media.getRepresentations()) {
324 MediaRepresentationDTO repDto = new MediaRepresentationDTO();
325 loadBaseData(config, rep, repDto);
326 repDto.setMimeType(rep.getMimeType());
327 repDto.setSuffix(rep.getSuffix());
328 if (!rep.getParts().isEmpty()) {
329 //TODO handle message if n(parts) > 1
330 MediaRepresentationPart part = rep.getParts().get(0);
331 repDto.setUri(part.getUri());
332 repDto.setClazz(part.getClass().getSimpleName());
333 repDto.setSize(part.getSize());
334 if (part.isInstanceOf(ImageFile.class)) {
335 ImageFile image = CdmBase.deproxy(part, ImageFile.class);
336 repDto.setHeight(image.getHeight());
337 repDto.setWidth(image.getWidth());
338 }
339 //TODO AudioFile etc.
340 }
341 representations.addItem(repDto);
342 }
343 if (representations.getCount() > 0) {
344 dto.setRepresentations(representations);
345 }
346 //TODO load representation data
347 container.addItem(dto);
348 }
349 }