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 addFieldInOrder(metadata);
79 this.outputFields.put(metadata.getOutputID(), metadata);
80 }
81
82
83
84
85
86
87
88 private void addFieldInOrder(final MetadataField metadata) {
89 removeFieldIfExists(metadata);
90
91
92 final ArrayList<MetadataField> orderedFields = new ArrayList<>();
93 final ArrayList<MetadataField> unorderedFields = new ArrayList<>();
94 for (final MetadataField field : fieldsInOrder) {
95 if (field.getOrder() != null) {
96 orderedFields.add(field);
97 } else {
98 unorderedFields.add(field);
99 }
100 }
101
102
103 if (metadata.getOrder() != null) {
104 orderedFields.add(metadata);
105 } else {
106 unorderedFields.add(metadata);
107 }
108
109
110 orderedFields.sort(Comparator.comparingInt(MetadataField::getOrder));
111
112
113 fieldsInOrder = new ArrayList<>(unorderedFields);
114
115
116 for (final MetadataField orderedField : orderedFields) {
117 final int index = orderedField.getOrder() < fieldsInOrder.size() ? orderedField.getOrder()
118 : fieldsInOrder.size();
119 fieldsInOrder.add(index, orderedField);
120 }
121 }
122
123 public void addEmptyField(final MetadataField metadataField, final ListProvidersService listProvidersService) {
124 addField(metadataField, Collections.emptyList(), Optional.empty(), listProvidersService);
125 }
126
127 public void addField(final MetadataField metadataField, final String value, final ListProvidersService
128 listProvidersService) {
129 addField(metadataField, Collections.singletonList(value), Optional.empty(), listProvidersService);
130 }
131
132 public void addField(final MetadataField metadataField, final Optional<String> valueOpt, final
133 Optional<ResourceListQuery> collectionQueryOverrideOpt, final ListProvidersService listProvidersService) {
134 if (valueOpt.isPresent()) {
135 addField(metadataField, Collections.singletonList(valueOpt.get()), collectionQueryOverrideOpt,
136 listProvidersService);
137 } else {
138 addField(metadataField, Collections.emptyList(), collectionQueryOverrideOpt, listProvidersService);
139 }
140 }
141
142
143
144
145 private static void setValueFromDCCatalog(
146 final List<String> filteredValues,
147 final MetadataField metadataField) {
148 if (filteredValues.isEmpty()) {
149 throw new IllegalArgumentException("Values cannot be empty");
150 }
151
152 if (filteredValues.size() > 1
153 && metadataField.getType() != MetadataField.Type.MIXED_TEXT
154 && metadataField.getType() != MetadataField.Type.ITERABLE_TEXT) {
155 logger.warn("Cannot put multiple values into a single-value field, only the last value is used. {}",
156 Arrays.toString(filteredValues.toArray()));
157 }
158
159 switch (metadataField.getType()) {
160 case BOOLEAN:
161 metadataField.setValue(Boolean.parseBoolean(Iterables.getLast(filteredValues)), false);
162 break;
163 case DATE:
164 if (metadataField.getPattern() == null) {
165 metadataField.setPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
166 }
167 metadataField.setValue(EncodingSchemeUtils.decodeDate(Iterables.getLast(filteredValues)), false);
168 break;
169 case DURATION:
170 final String value = Iterables.getLast(filteredValues);
171 final DCMIPeriod period = EncodingSchemeUtils.decodePeriod(value);
172 if (period == null)
173 throw new IllegalArgumentException("period couldn't be parsed: " + value);
174 final long longValue = period.getEnd().getTime() - period.getStart().getTime();
175 metadataField.setValue(Long.toString(longValue), false);
176 break;
177 case ITERABLE_TEXT:
178 case MIXED_TEXT:
179 metadataField.setValue(filteredValues, false);
180 break;
181 case LONG:
182 metadataField.setValue(Long.parseLong(Iterables.getLast(filteredValues)), false);
183 break;
184 case START_DATE:
185 if (metadataField.getPattern() == null) {
186 metadataField.setPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
187 }
188 metadataField.setValue(Iterables.getLast(filteredValues), false);
189 break;
190 case TEXT:
191 case ORDERED_TEXT:
192 case TEXT_LONG:
193 metadataField.setValue(Iterables.getLast(filteredValues), false);
194 break;
195 default:
196 throw new IllegalArgumentException("Unknown metadata type! " + metadataField.getType());
197 }
198 }
199
200 public void addField(final MetadataField metadataField, final List<String> values, final ListProvidersService
201 listProvidersService) {
202 addField(metadataField, values, Optional.empty(), listProvidersService);
203 }
204
205 public void addField(final MetadataField metadataField, final List<String> values, final Optional<ResourceListQuery>
206 collectionQueryOverrideOpt, final ListProvidersService listProvidersService) {
207 final List<String> filteredValues = values.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());
208
209 if (!filteredValues.isEmpty()) {
210 setValueFromDCCatalog(filteredValues, metadataField);
211 }
212
213 metadataField.setIsTranslatable(getCollectionIsTranslatable(metadataField, listProvidersService));
214 metadataField.setCollection(getCollection(metadataField, listProvidersService, collectionQueryOverrideOpt));
215
216 addField(metadataField);
217 }
218
219 private static Boolean getCollectionIsTranslatable(
220 final MetadataField metadataField,
221 final ListProvidersService listProvidersService) {
222 if (listProvidersService != null && metadataField.getListprovider() != null) {
223 try {
224 return listProvidersService.isTranslatable(metadataField.getListprovider());
225 } catch (final ListProviderException ex) {
226
227
228 }
229 }
230 return null;
231 }
232
233 private static Map<String, String> getCollection(final MetadataField metadataField, final ListProvidersService
234 listProvidersService, final Optional<ResourceListQuery> collectionQueryOverrideOpt) {
235 try {
236 if (listProvidersService != null && metadataField.getListprovider() != null) {
237
238
239 ResourceListQuery resourceListQuery;
240 if (collectionQueryOverrideOpt.isPresent()) {
241 resourceListQuery = collectionQueryOverrideOpt.get();
242
243
244 Optional<Integer> limit = resourceListQuery.getLimit();
245 if (limit.isPresent() && limit.get() == 0) {
246 return Collections.emptyMap();
247 }
248 } else {
249 resourceListQuery = new ResourceListQueryImpl();
250 }
251
252 return listProvidersService.getList(metadataField.getListprovider(), resourceListQuery, true);
253 }
254 return null;
255 } catch (final ListProviderException e) {
256 logger.warn("Unable to set collection on metadata because", e);
257 return null;
258 }
259 }
260
261
262
263
264
265
266
267 private void removeFieldIfExists(final MetadataField metadata) {
268 int index = -1;
269 for (final MetadataField field : fieldsInOrder) {
270 if (field.getInputID().equalsIgnoreCase(metadata.getInputID())
271 && field.getOutputID().equalsIgnoreCase(metadata.getOutputID())) {
272 index = fieldsInOrder.indexOf(field);
273 }
274 }
275
276 if (index >= 0) {
277 fieldsInOrder.remove(index);
278 }
279 }
280
281 public void removeField(final MetadataField metadata) {
282 if (metadata == null)
283 throw new IllegalArgumentException("The metadata must not be null.");
284 this.fieldsInOrder.remove(metadata);
285 this.outputFields.remove(metadata.getOutputID());
286 }
287
288 public List<MetadataField> getFields() {
289 return this.fieldsInOrder;
290 }
291
292 public void updateStringField(final MetadataField current, final String value) {
293 if (current.getValue() != null && !(current.getValue() instanceof String)) {
294 throw new IllegalArgumentException("Unable to update a field to a different type than String with this method!");
295 }
296 removeField(current);
297 final MetadataField field = new MetadataField(current);
298 field.setValue(value);
299 addField(field);
300 }
301
302 public boolean isUpdated() {
303 for (final MetadataField field : fieldsInOrder) {
304 if (field.isUpdated()) {
305 return true;
306 }
307 }
308 return false;
309 }
310
311 }