1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.metadata.dublincore;
23
24 import org.opencastproject.list.api.ListProviderException;
25 import org.opencastproject.list.api.ListProvidersService;
26 import org.opencastproject.list.api.ResourceListQuery;
27 import org.opencastproject.list.impl.ResourceListQueryImpl;
28
29 import com.google.common.collect.Iterables;
30
31 import org.apache.commons.lang3.StringUtils;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.Collections;
38 import java.util.Comparator;
39 import java.util.HashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Optional;
43 import java.util.stream.Collectors;
44
45 public class DublinCoreMetadataCollection {
46 private static final Logger logger = LoggerFactory.getLogger(DublinCoreMetadataCollection.class);
47
48
49 private List<MetadataField> fieldsInOrder = new ArrayList<>();
50 private final Map<String, MetadataField> outputFields = new HashMap<>();
51
52 public DublinCoreMetadataCollection() {
53 this(Collections.emptyList());
54 }
55
56 public DublinCoreMetadataCollection(final Iterable<MetadataField> fields) {
57 for (final MetadataField field : fields) {
58 addField(field);
59 }
60 }
61
62 public DublinCoreMetadataCollection(final DublinCoreMetadataCollection c) {
63 this(c.fieldsInOrder);
64 }
65
66 public DublinCoreMetadataCollection readOnlyCopy() {
67 return new DublinCoreMetadataCollection(this.fieldsInOrder.stream().map(MetadataField::readOnlyCopy)
68 .collect(Collectors.toList()));
69 }
70
71 public Map<String, MetadataField> getOutputFields() {
72 return outputFields;
73 }
74
75 public void addField(final MetadataField metadata) {
76 if (metadata == null) {
77 throw new IllegalArgumentException("The metadata must not be null.");
78 }
79 addFieldInOrder(metadata);
80 this.outputFields.put(metadata.getOutputID(), metadata);
81 }
82
83
84
85
86
87
88
89 private void addFieldInOrder(final MetadataField metadata) {
90 removeFieldIfExists(metadata);
91
92
93 final ArrayList<MetadataField> orderedFields = new ArrayList<>();
94 final ArrayList<MetadataField> unorderedFields = new ArrayList<>();
95 for (final MetadataField field : fieldsInOrder) {
96 if (field.getOrder() != null) {
97 orderedFields.add(field);
98 } else {
99 unorderedFields.add(field);
100 }
101 }
102
103
104 if (metadata.getOrder() != null) {
105 orderedFields.add(metadata);
106 } else {
107 unorderedFields.add(metadata);
108 }
109
110
111 orderedFields.sort(Comparator.comparingInt(MetadataField::getOrder));
112
113
114 fieldsInOrder = new ArrayList<>(unorderedFields);
115
116
117 for (final MetadataField orderedField : orderedFields) {
118 final int index = orderedField.getOrder() < fieldsInOrder.size() ? orderedField.getOrder()
119 : fieldsInOrder.size();
120 fieldsInOrder.add(index, orderedField);
121 }
122 }
123
124 public void addEmptyField(final MetadataField metadataField, final ListProvidersService listProvidersService) {
125 addField(metadataField, Collections.emptyList(), Optional.empty(), listProvidersService);
126 }
127
128 public void addField(final MetadataField metadataField, final String value, final ListProvidersService
129 listProvidersService) {
130 addField(metadataField, Collections.singletonList(value), Optional.empty(), listProvidersService);
131 }
132
133 public void addField(final MetadataField metadataField, final Optional<String> valueOpt, final
134 Optional<ResourceListQuery> collectionQueryOverrideOpt, final ListProvidersService listProvidersService) {
135 if (valueOpt.isPresent()) {
136 addField(metadataField, Collections.singletonList(valueOpt.get()), collectionQueryOverrideOpt,
137 listProvidersService);
138 } else {
139 addField(metadataField, Collections.emptyList(), collectionQueryOverrideOpt, listProvidersService);
140 }
141 }
142
143
144
145
146 private static void setValueFromDCCatalog(
147 final List<String> filteredValues,
148 final MetadataField metadataField) {
149 if (filteredValues.isEmpty()) {
150 throw new IllegalArgumentException("Values cannot be empty");
151 }
152
153 if (filteredValues.size() > 1
154 && metadataField.getType() != MetadataField.Type.MIXED_TEXT
155 && metadataField.getType() != MetadataField.Type.ITERABLE_TEXT) {
156 logger.warn("Cannot put multiple values into a single-value field, only the last value is used. {}",
157 Arrays.toString(filteredValues.toArray()));
158 }
159
160 switch (metadataField.getType()) {
161 case BOOLEAN:
162 metadataField.setValue(Boolean.parseBoolean(Iterables.getLast(filteredValues)), false);
163 break;
164 case DATE:
165 if (metadataField.getPattern() == null) {
166 metadataField.setPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
167 }
168 metadataField.setValue(EncodingSchemeUtils.decodeDate(Iterables.getLast(filteredValues)), false);
169 break;
170 case DURATION:
171 final String value = Iterables.getLast(filteredValues);
172 final DCMIPeriod period = EncodingSchemeUtils.decodePeriod(value);
173 if (period == null) {
174 throw new IllegalArgumentException("period couldn't be parsed: " + value);
175 }
176 final long longValue = period.getEnd().getTime() - period.getStart().getTime();
177 metadataField.setValue(Long.toString(longValue), false);
178 break;
179 case ITERABLE_TEXT:
180 case MIXED_TEXT:
181 metadataField.setValue(filteredValues, false);
182 break;
183 case LONG:
184 metadataField.setValue(Long.parseLong(Iterables.getLast(filteredValues)), false);
185 break;
186 case START_DATE:
187 if (metadataField.getPattern() == null) {
188 metadataField.setPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
189 }
190 metadataField.setValue(Iterables.getLast(filteredValues), false);
191 break;
192 case TEXT:
193 case ORDERED_TEXT:
194 case TEXT_LONG:
195 metadataField.setValue(Iterables.getLast(filteredValues), false);
196 break;
197 default:
198 throw new IllegalArgumentException("Unknown metadata type! " + metadataField.getType());
199 }
200 }
201
202 public void addField(final MetadataField metadataField, final List<String> values, final ListProvidersService
203 listProvidersService) {
204 addField(metadataField, values, Optional.empty(), listProvidersService);
205 }
206
207 public void addField(final MetadataField metadataField, final List<String> values, final Optional<ResourceListQuery>
208 collectionQueryOverrideOpt, final ListProvidersService listProvidersService) {
209 final List<String> filteredValues = values.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());
210
211 if (!filteredValues.isEmpty()) {
212 setValueFromDCCatalog(filteredValues, metadataField);
213 }
214
215 metadataField.setIsTranslatable(getCollectionIsTranslatable(metadataField, listProvidersService));
216 metadataField.setCollection(getCollection(metadataField, listProvidersService, collectionQueryOverrideOpt));
217
218 addField(metadataField);
219 }
220
221 private static Boolean getCollectionIsTranslatable(
222 final MetadataField metadataField,
223 final ListProvidersService listProvidersService) {
224 if (listProvidersService != null && metadataField.getListprovider() != null) {
225 try {
226 return listProvidersService.isTranslatable(metadataField.getListprovider());
227 } catch (final ListProviderException ex) {
228
229
230 }
231 }
232 return null;
233 }
234
235 private static Map<String, String> getCollection(final MetadataField metadataField, final ListProvidersService
236 listProvidersService, final Optional<ResourceListQuery> collectionQueryOverrideOpt) {
237 try {
238 if (listProvidersService != null && metadataField.getListprovider() != null) {
239
240
241 ResourceListQuery resourceListQuery;
242 if (collectionQueryOverrideOpt.isPresent()) {
243 resourceListQuery = collectionQueryOverrideOpt.get();
244
245
246 Optional<Integer> limit = resourceListQuery.getLimit();
247 if (limit.isPresent() && limit.get() == 0) {
248 return Collections.emptyMap();
249 }
250 } else {
251 resourceListQuery = new ResourceListQueryImpl();
252 }
253
254 return listProvidersService.getList(metadataField.getListprovider(), resourceListQuery, true);
255 }
256 return null;
257 } catch (final ListProviderException e) {
258 logger.warn("Unable to set collection on metadata because", e);
259 return null;
260 }
261 }
262
263
264
265
266
267
268
269 private void removeFieldIfExists(final MetadataField metadata) {
270 int index = -1;
271 for (final MetadataField field : fieldsInOrder) {
272 if (field.getInputID().equalsIgnoreCase(metadata.getInputID())
273 && field.getOutputID().equalsIgnoreCase(metadata.getOutputID())) {
274 index = fieldsInOrder.indexOf(field);
275 }
276 }
277
278 if (index >= 0) {
279 fieldsInOrder.remove(index);
280 }
281 }
282
283 public void removeField(final MetadataField metadata) {
284 if (metadata == null) {
285 throw new IllegalArgumentException("The metadata must not be null.");
286 }
287 this.fieldsInOrder.remove(metadata);
288 this.outputFields.remove(metadata.getOutputID());
289 }
290
291 public List<MetadataField> getFields() {
292 return this.fieldsInOrder;
293 }
294
295 public void updateStringField(final MetadataField current, final String value) {
296 if (current.getValue() != null && !(current.getValue() instanceof String)) {
297 throw new IllegalArgumentException("Unable to update a field to a different type than String with this method!");
298 }
299 removeField(current);
300 final MetadataField field = new MetadataField(current);
301 field.setValue(value);
302 addField(field);
303 }
304
305 public boolean isUpdated() {
306 for (final MetadataField field : fieldsInOrder) {
307 if (field.isUpdated()) {
308 return true;
309 }
310 }
311 return false;
312 }
313
314 }