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 import org.opencastproject.util.data.Option;
29
30 import com.google.common.collect.Iterables;
31
32 import org.apache.commons.lang3.StringUtils;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.Comparator;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Optional;
44 import java.util.stream.Collectors;
45
46 public class DublinCoreMetadataCollection {
47 private static final Logger logger = LoggerFactory.getLogger(DublinCoreMetadataCollection.class);
48
49
50 private List<MetadataField> fieldsInOrder = new ArrayList<>();
51 private final Map<String, MetadataField> outputFields = new HashMap<>();
52
53 public DublinCoreMetadataCollection() {
54 this(Collections.emptyList());
55 }
56
57 public DublinCoreMetadataCollection(final Iterable<MetadataField> fields) {
58 for (final MetadataField field : fields) {
59 addField(field);
60 }
61 }
62
63 public DublinCoreMetadataCollection(final DublinCoreMetadataCollection c) {
64 this(c.fieldsInOrder);
65 }
66
67 public DublinCoreMetadataCollection readOnlyCopy() {
68 return new DublinCoreMetadataCollection(this.fieldsInOrder.stream().map(MetadataField::readOnlyCopy)
69 .collect(Collectors.toList()));
70 }
71
72 public Map<String, MetadataField> getOutputFields() {
73 return outputFields;
74 }
75
76 public void addField(final MetadataField metadata) {
77 if (metadata == null)
78 throw new IllegalArgumentException("The metadata must not be null.");
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 final long longValue = period.getEnd().getTime() - period.getStart().getTime();
176 metadataField.setValue(Long.toString(longValue), false);
177 break;
178 case ITERABLE_TEXT:
179 case MIXED_TEXT:
180 metadataField.setValue(filteredValues, false);
181 break;
182 case LONG:
183 metadataField.setValue(Long.parseLong(Iterables.getLast(filteredValues)), false);
184 break;
185 case START_DATE:
186 if (metadataField.getPattern() == null) {
187 metadataField.setPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
188 }
189 metadataField.setValue(Iterables.getLast(filteredValues), false);
190 break;
191 case TEXT:
192 case ORDERED_TEXT:
193 case TEXT_LONG:
194 metadataField.setValue(Iterables.getLast(filteredValues), false);
195 break;
196 default:
197 throw new IllegalArgumentException("Unknown metadata type! " + metadataField.getType());
198 }
199 }
200
201 public void addField(final MetadataField metadataField, final List<String> values, final ListProvidersService
202 listProvidersService) {
203 addField(metadataField, values, Optional.empty(), listProvidersService);
204 }
205
206 public void addField(final MetadataField metadataField, final List<String> values, final Optional<ResourceListQuery>
207 collectionQueryOverrideOpt, final ListProvidersService listProvidersService) {
208 final List<String> filteredValues = values.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());
209
210 if (!filteredValues.isEmpty()) {
211 setValueFromDCCatalog(filteredValues, metadataField);
212 }
213
214 metadataField.setIsTranslatable(getCollectionIsTranslatable(metadataField, listProvidersService));
215 metadataField.setCollection(getCollection(metadataField, listProvidersService, collectionQueryOverrideOpt));
216
217 addField(metadataField);
218 }
219
220 private static Boolean getCollectionIsTranslatable(
221 final MetadataField metadataField,
222 final ListProvidersService listProvidersService) {
223 if (listProvidersService != null && metadataField.getListprovider() != null) {
224 try {
225 return listProvidersService.isTranslatable(metadataField.getListprovider());
226 } catch (final ListProviderException ex) {
227
228
229 }
230 }
231 return null;
232 }
233
234 private static Map<String, String> getCollection(final MetadataField metadataField, final ListProvidersService
235 listProvidersService, final Optional<ResourceListQuery> collectionQueryOverrideOpt) {
236 try {
237 if (listProvidersService != null && metadataField.getListprovider() != null) {
238
239
240 ResourceListQuery resourceListQuery;
241 if (collectionQueryOverrideOpt.isPresent()) {
242 resourceListQuery = collectionQueryOverrideOpt.get();
243
244
245 Option<Integer> limit = resourceListQuery.getLimit();
246 if (limit.isSome() && limit.get() == 0) {
247 return Collections.emptyMap();
248 }
249 } else {
250 resourceListQuery = new ResourceListQueryImpl();
251 }
252
253 return listProvidersService.getList(metadataField.getListprovider(), resourceListQuery, true);
254 }
255 return null;
256 } catch (final ListProviderException e) {
257 logger.warn("Unable to set collection on metadata because", e);
258 return null;
259 }
260 }
261
262
263
264
265
266
267
268 private void removeFieldIfExists(final MetadataField metadata) {
269 int index = -1;
270 for (final MetadataField field : fieldsInOrder) {
271 if (field.getInputID().equalsIgnoreCase(metadata.getInputID())
272 && field.getOutputID().equalsIgnoreCase(metadata.getOutputID())) {
273 index = fieldsInOrder.indexOf(field);
274 }
275 }
276
277 if (index >= 0) {
278 fieldsInOrder.remove(index);
279 }
280 }
281
282 public void removeField(final MetadataField metadata) {
283 if (metadata == null)
284 throw new IllegalArgumentException("The metadata must not be null.");
285 this.fieldsInOrder.remove(metadata);
286 this.outputFields.remove(metadata.getOutputID());
287 }
288
289 public List<MetadataField> getFields() {
290 return this.fieldsInOrder;
291 }
292
293 public void updateStringField(final MetadataField current, final String value) {
294 if (current.getValue() != null && !(current.getValue() instanceof String)) {
295 throw new IllegalArgumentException("Unable to update a field to a different type than String with this method!");
296 }
297 removeField(current);
298 final MetadataField field = new MetadataField(current);
299 field.setValue(value);
300 addField(field);
301 }
302
303 public boolean isUpdated() {
304 for (final MetadataField field : fieldsInOrder) {
305 if (field.isUpdated()) {
306 return true;
307 }
308 }
309 return false;
310 }
311
312 }