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.statistics.export.impl;
23
24 import static org.opencastproject.util.data.functions.Misc.chuck;
25
26 import org.opencastproject.assetmanager.api.AssetManager;
27 import org.opencastproject.elasticsearch.api.SearchIndexException;
28 import org.opencastproject.elasticsearch.api.SearchQuery;
29 import org.opencastproject.elasticsearch.api.SearchResult;
30 import org.opencastproject.elasticsearch.api.SearchResultItem;
31 import org.opencastproject.elasticsearch.index.ElasticsearchIndex;
32 import org.opencastproject.elasticsearch.index.objects.event.Event;
33 import org.opencastproject.elasticsearch.index.objects.event.EventSearchQuery;
34 import org.opencastproject.elasticsearch.index.objects.series.Series;
35 import org.opencastproject.elasticsearch.index.objects.series.SeriesSearchQuery;
36 import org.opencastproject.index.service.api.IndexService;
37 import org.opencastproject.mediapackage.MediaPackage;
38 import org.opencastproject.metadata.dublincore.DublinCoreMetadataCollection;
39 import org.opencastproject.metadata.dublincore.MetadataField;
40 import org.opencastproject.security.api.Organization;
41 import org.opencastproject.security.api.SecurityService;
42 import org.opencastproject.security.api.UnauthorizedException;
43 import org.opencastproject.statistics.api.DataResolution;
44 import org.opencastproject.statistics.api.StatisticsProvider;
45 import org.opencastproject.statistics.api.StatisticsService;
46 import org.opencastproject.statistics.api.TimeSeries;
47 import org.opencastproject.statistics.api.TimeSeriesProvider;
48 import org.opencastproject.statistics.export.api.DetailLevel;
49 import org.opencastproject.statistics.export.api.StatisticsExportService;
50 import org.opencastproject.util.ConfigurationException;
51 import org.opencastproject.util.NotFoundException;
52
53 import org.apache.commons.csv.CSVFormat;
54 import org.apache.commons.csv.CSVPrinter;
55 import org.osgi.service.cm.ManagedService;
56 import org.osgi.service.component.ComponentContext;
57 import org.osgi.service.component.annotations.Activate;
58 import org.osgi.service.component.annotations.Component;
59 import org.osgi.service.component.annotations.Deactivate;
60 import org.osgi.service.component.annotations.Reference;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import java.io.IOException;
65 import java.io.StringWriter;
66 import java.time.Instant;
67 import java.time.LocalDateTime;
68 import java.time.ZoneId;
69 import java.time.format.DateTimeFormatter;
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Collection;
73 import java.util.Collections;
74 import java.util.Dictionary;
75 import java.util.HashMap;
76 import java.util.List;
77 import java.util.Map;
78 import java.util.Optional;
79 import java.util.stream.Collectors;
80 import java.util.stream.Stream;
81
82 @Component(
83 immediate = true,
84 service = { ManagedService.class,StatisticsExportService.class },
85 property = {
86 "service.description=Statistics Export Service"
87 }
88 )
89 public class StatisticsExportServiceImpl implements StatisticsExportService, ManagedService {
90
91
92 private static final Logger logger = LoggerFactory.getLogger(StatisticsExportServiceImpl.class);
93 private static final String[] header = {"ID", "Name", "Date", "Value"};
94 private static final String CFG_KEY_SERIES_TO_EVENT_PROVIDER_MAPPINGS = "series.to.event.provider.mappings";
95 private static final String CFG_KEY_ORGANIZATION_TO_EVENT_PROVIDER_MAPPINGS
96 = "organization.to.event.provider.mappings";
97 private static final String CFG_KEY_ORGANIZATION_TO_SERIES_PROVIDER_MAPPINGS
98 = "organization.to.series.provider.mappings";
99
100
101 private Map<String, String> seriesToEventProviderMapping = new HashMap<>();
102 private Map<String, String> organizationToEventProviderMapping = new HashMap<>();
103 private Map<String, String> organizationToSeriesProviderMapping = new HashMap<>();
104
105 private IndexService indexService;
106 private SecurityService securityService;
107 private StatisticsService statisticsService;
108 private AssetManager assetManager;
109
110 @Override
111 public void updated(Dictionary<String, ?> dictionary) {
112 final String seriesToEventProviderMappings = (String) dictionary.get(CFG_KEY_SERIES_TO_EVENT_PROVIDER_MAPPINGS);
113 if (seriesToEventProviderMappings != null) {
114 this.seriesToEventProviderMapping = getMapping(seriesToEventProviderMappings);
115 }
116 final String organizationToEventProviderMappings
117 = (String) dictionary.get(CFG_KEY_ORGANIZATION_TO_EVENT_PROVIDER_MAPPINGS);
118 if (organizationToEventProviderMappings != null) {
119 this.organizationToEventProviderMapping = getMapping(organizationToEventProviderMappings);
120 }
121 final String organizationToSeriesProviderMappings
122 = (String) dictionary.get(CFG_KEY_ORGANIZATION_TO_SERIES_PROVIDER_MAPPINGS);
123 if (organizationToSeriesProviderMappings != null) {
124 this.organizationToSeriesProviderMapping = getMapping(organizationToSeriesProviderMappings);
125 }
126 }
127
128 private Map<String, String> getMapping(String seriesProviderMappings) {
129 return Arrays.stream(seriesProviderMappings.split(","))
130 .peek(s -> {
131 if (!s.contains(":")) {
132 throw new ConfigurationException("Missing ':' in mapping between providers: " + s);
133 }
134 })
135 .collect(Collectors.toMap(
136 s -> s.split(":")[0], s -> s.split(":")[1]
137 ));
138 }
139
140 @Activate
141 public void activate(ComponentContext cc) {
142 logger.info("Activating Statistics Service");
143 }
144
145 @Deactivate
146 public void deactivate(ComponentContext cc) {
147 logger.info("Deactivating Statistics Service");
148 }
149
150 @Reference
151 public void setIndexService(IndexService indexService) {
152 this.indexService = indexService;
153 }
154
155 @Reference
156 public void setStatisticsService(StatisticsService statisticsService) {
157 this.statisticsService = statisticsService;
158 }
159
160 @Reference
161 public void setSecurityService(SecurityService securityService) {
162 this.securityService = securityService;
163 }
164
165 @Reference
166 public void setAssetManager(final AssetManager assetManager) {
167 this.assetManager = assetManager;
168 }
169
170 private static String formatDate(final String dateStr, DataResolution dataResolution, ZoneId zoneId) {
171 final LocalDateTime ldt = LocalDateTime.ofInstant(Instant.parse(dateStr), zoneId);
172 DateTimeFormatter formatter = null;
173 switch (dataResolution) {
174 case HOURLY:
175 formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:00");
176 return formatter.format(ldt);
177 case DAILY:
178 formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd");
179 return formatter.format(ldt);
180 case WEEKLY:
181 formatter = DateTimeFormatter.ofPattern("uuuu-ww");
182 return formatter.format(ldt);
183 case MONTHLY:
184 formatter = DateTimeFormatter.ofPattern("uuuu-MM");
185 return formatter.format(ldt);
186 case YEARLY:
187 formatter = DateTimeFormatter.ofPattern("uuuu");
188 return formatter.format(ldt);
189 default:
190 throw new IllegalStateException("Unexpected value: " + dataResolution);
191 }
192 }
193
194
195 @Override
196 public String getCSV(
197 StatisticsProvider provider,
198 String resourceId,
199 Instant from,
200 Instant to,
201 DataResolution dataResolution,
202 ElasticsearchIndex index,
203 ZoneId zoneId
204 ) throws SearchIndexException, UnauthorizedException, NotFoundException {
205 if (!(provider instanceof TimeSeriesProvider)) {
206 throw new IllegalStateException("CSV export not supported for provider of type " + provider.getClass().getName());
207 }
208 final StringWriter stringWriter = new StringWriter();
209 try (CSVPrinter printer = CSVFormat.RFC4180.print(stringWriter)) {
210 switch (provider.getResourceType()) {
211 case EPISODE:
212 printEvent(provider, resourceId, from, to, dataResolution, index, zoneId, printer, false, 0, 0);
213 break;
214 case SERIES:
215 if (seriesToEventProviderMapping.containsKey(provider.getId())) {
216
217 printSeriesEvents(provider, resourceId, from, to, dataResolution, index, zoneId, printer, false,
218 0, 0, Collections.emptyMap());
219 } else {
220
221 printSeries(provider, resourceId, from, to, dataResolution, index, zoneId, printer, false, 0, 0);
222 }
223 break;
224 case ORGANIZATION:
225 if (organizationToEventProviderMapping.containsKey(provider.getId())) {
226
227 printOrganizationEvents(provider, resourceId, from, to, dataResolution, index, zoneId, printer, false,
228 0, 0, Collections.emptyMap());
229 } else if (organizationToSeriesProviderMapping.containsKey(provider.getId())) {
230
231 printOrganizationSeries(provider, resourceId, from, to, dataResolution, index, zoneId, printer, false,
232 0, 0, Collections.emptyMap());
233 } else {
234 printOrganization(provider, resourceId, from, to, dataResolution, zoneId, printer, 0, 0);
235 }
236 break;
237 default:
238 throw new IllegalStateException("Unknown resource type: " + provider.getResourceType().name());
239 }
240 } catch (IOException e) {
241 return chuck(e);
242 }
243 return stringWriter.toString();
244 }
245
246 @Override
247 public String getCSV(StatisticsProvider provider, String resourceId, Instant from, Instant to, DataResolution
248 dataResolution, ElasticsearchIndex index, ZoneId zoneId, boolean fullMetadata, DetailLevel detailLevel,
249 int limit, int offset, Map<String, String> filters)
250 throws SearchIndexException, UnauthorizedException, NotFoundException {
251 if (!(provider instanceof TimeSeriesProvider)) {
252 throw new IllegalStateException("CSV export not supported for provider of type " + provider.getClass().getName());
253 }
254 final StringWriter stringWriter = new StringWriter();
255 try (CSVPrinter printer = CSVFormat.RFC4180.print(stringWriter)) {
256 switch (provider.getResourceType()) {
257 case EPISODE:
258 printEvent(provider, resourceId, from, to,
259 dataResolution, index, zoneId, printer, fullMetadata, limit, offset);
260 break;
261 case SERIES:
262 if (detailLevel == DetailLevel.EPISODE) {
263
264 printSeriesEvents(provider, resourceId, from, to, dataResolution, index, zoneId, printer, fullMetadata,
265 limit, offset, filters);
266 } else {
267
268 printSeries(provider, resourceId, from, to, dataResolution,
269 index, zoneId, printer, fullMetadata, limit, offset);
270 }
271 break;
272 case ORGANIZATION:
273 if (detailLevel == DetailLevel.EPISODE) {
274
275
276 printOrganizationEvents(provider, resourceId, from, to,
277 dataResolution, index, zoneId, printer, fullMetadata,
278 limit, offset, filters);
279 } else if (detailLevel == DetailLevel.SERIES) {
280
281
282 printOrganizationSeries(provider, resourceId, from, to,
283 dataResolution, index, zoneId, printer, fullMetadata,
284 limit, offset, filters);
285 } else {
286 printOrganization(provider, resourceId, from, to, dataResolution, zoneId, printer, limit, offset);
287 }
288 break;
289 default:
290 throw new IllegalStateException("Unknown resource type: " + provider.getResourceType().name());
291 }
292 } catch (IOException e) {
293 return chuck(e);
294 }
295 return stringWriter.toString();
296 }
297
298
299 private void printEvent(
300 StatisticsProvider provider,
301 String resourceId,
302 Instant from,
303 Instant to,
304 DataResolution dataResolution,
305 ElasticsearchIndex index,
306 ZoneId zoneId,
307 CSVPrinter printer,
308 boolean fullMetaData,
309 int limit,
310 int offset
311 ) throws IOException, SearchIndexException, NotFoundException {
312 if (offset != 0) {
313 return;
314 }
315 final Optional<Event> event = indexService.getEvent(resourceId, index);
316 if (!event.isPresent()) {
317 throw new NotFoundException("Event not found in index: " + resourceId);
318 }
319 final TimeSeries dataEvent = statisticsService.getTimeSeriesData(
320 provider, resourceId, from, to, dataResolution, zoneId);
321 if (fullMetaData) {
322 this.printFullEventData(printer, dataEvent, dataResolution, resourceId, zoneId, true);
323 } else {
324 printData(printer, dataEvent, dataResolution, resourceId, event.get().getTitle(), zoneId, true);
325 }
326 }
327
328 private void printSeries(StatisticsProvider provider, String resourceId, Instant from, Instant to,
329 DataResolution dataResolution, ElasticsearchIndex index, ZoneId zoneId, CSVPrinter printer,
330 boolean fullMetadata, int limit, int offset)
331 throws SearchIndexException, NotFoundException, IOException {
332 if (offset != 0) {
333 return;
334 }
335 final Optional<Series> series = index.getSeries(
336 resourceId, securityService.getOrganization().getId(), securityService.getUser());
337 if (!series.isPresent()) {
338 throw new NotFoundException("Series not found in index: " + resourceId);
339 }
340 final TimeSeries dataSeries = statisticsService.getTimeSeriesData(
341 provider, resourceId, from, to, dataResolution, zoneId);
342 if (fullMetadata) {
343 this.printFullSeriesData(printer, dataSeries, dataResolution, resourceId, zoneId, true);
344 } else {
345 printData(printer, dataSeries, dataResolution, resourceId, series.get().getTitle(), zoneId, true);
346 }
347 }
348
349 private void printSeriesEvents(
350 StatisticsProvider provider,
351 String resourceId,
352 Instant from,
353 Instant to,
354 DataResolution dataResolution,
355 ElasticsearchIndex index,
356 ZoneId zoneId,
357 CSVPrinter printer,
358 boolean fullMetadata,
359 int limit,
360 int offset,
361 Map<String, String> filters
362 ) throws SearchIndexException, IOException {
363 final String eventProviderId = seriesToEventProviderMapping.get(provider.getId());
364 final StatisticsProvider eventProvider = statisticsService.getProvider(eventProviderId)
365 .orElseThrow(() -> new IllegalStateException(
366 "The configured provider " + eventProviderId + " is not available."));
367 EventSearchQuery query = (EventSearchQuery) new EventSearchQuery(securityService.getOrganization().getId(),
368 securityService.getUser()).withSeriesId(resourceId).withLimit(limit).withOffset(offset);
369 for (Map.Entry<String, String> filter: filters.entrySet()) {
370 query = (EventSearchQuery) applyFilter(filter.getKey(), filter.getValue(), query);
371 }
372
373 final SearchResult<Event> result = index.getByQuery(query);
374 boolean first = offset == 0;
375 for (SearchResultItem<Event> currentEvent : result.getItems()) {
376 final TimeSeries dataEvent = statisticsService.getTimeSeriesData(eventProvider,
377 currentEvent.getSource().getIdentifier(), from, to, dataResolution, zoneId);
378 if (fullMetadata) {
379 this.printFullEventData(printer, dataEvent, dataResolution,
380 currentEvent.getSource().getIdentifier(), zoneId, first);
381 } else {
382 printData(printer, dataEvent, dataResolution, currentEvent.getSource().getIdentifier(),
383 currentEvent.getSource().getTitle(), zoneId, first);
384 }
385 first = false;
386 }
387 }
388
389 private void printOrganization(
390 StatisticsProvider provider,
391 String resourceId,
392 Instant from,
393 Instant to,
394 DataResolution dataResolution,
395 ZoneId zoneId,
396 CSVPrinter printer,
397 int limit,
398 int offset
399 ) throws UnauthorizedException, IOException {
400 if (offset != 0) {
401 return;
402 }
403 final Organization organization = securityService.getOrganization();
404 if (!resourceId.equals(organization.getId())) {
405 throw new UnauthorizedException("Can only export CSV statistics for own organization.");
406 }
407 final TimeSeries dataOrg = statisticsService.getTimeSeriesData(
408 provider, resourceId, from, to, dataResolution, zoneId);
409 printData(printer, dataOrg, dataResolution, resourceId, organization.getName(), zoneId, true);
410 }
411
412 private void printOrganizationEvents(
413 StatisticsProvider provider,
414 String resourceId,
415 Instant from,
416 Instant to,
417 DataResolution dataResolution,
418 ElasticsearchIndex index,
419 ZoneId zoneId,
420 CSVPrinter printer,
421 boolean fullMetadata,
422 int limit,
423 int offset,
424 Map<String, String> filters
425 ) throws UnauthorizedException, SearchIndexException, IOException {
426
427 final Organization organization = securityService.getOrganization();
428 if (!resourceId.equals(organization.getId())) {
429 throw new UnauthorizedException("Can only export CSV statistics for own organization.");
430 }
431
432 final String eventProviderId = organizationToEventProviderMapping.get(provider.getId());
433 final StatisticsProvider eventProvider = statisticsService.getProvider(eventProviderId)
434 .orElseThrow(() -> new IllegalStateException(
435 "The configured provider " + eventProviderId + " is not available."));
436 EventSearchQuery query = (EventSearchQuery) new EventSearchQuery(securityService.getOrganization().getId(),
437 securityService.getUser()).withLimit(limit).withOffset(offset);
438 for (Map.Entry<String, String> filter: filters.entrySet()) {
439 query = (EventSearchQuery) applyFilter(filter.getKey(), filter.getValue(), query);
440 }
441 final SearchResult<Event> result = index.getByQuery(query);
442 boolean first = offset == 0;
443 for (SearchResultItem<Event> currentEvent : result.getItems()) {
444 final TimeSeries dataEvent = statisticsService.getTimeSeriesData(eventProvider,
445 currentEvent.getSource().getIdentifier(), from, to, dataResolution, zoneId);
446 if (fullMetadata) {
447 this.printFullEventData(printer, dataEvent, dataResolution,
448 currentEvent.getSource().getIdentifier(), zoneId, first);
449 } else {
450 printData(printer, dataEvent, dataResolution, currentEvent.getSource().getIdentifier(),
451 currentEvent.getSource().getTitle(), zoneId, first);
452 }
453 first = false;
454 }
455 }
456
457
458 private void printOrganizationSeries(
459 StatisticsProvider provider,
460 String resourceId,
461 Instant from,
462 Instant to,
463 DataResolution dataResolution,
464 ElasticsearchIndex index,
465 ZoneId zoneId,
466 CSVPrinter printer,
467 boolean fullMetadata,
468 int limit,
469 int offset,
470 Map<String, String> filters
471 ) throws UnauthorizedException, SearchIndexException, IOException {
472
473 final Organization organization = securityService.getOrganization();
474 if (!resourceId.equals(organization.getId())) {
475 throw new UnauthorizedException("Can only export CSV statistics for own organization.");
476 }
477
478 final String seriesProviderId = organizationToSeriesProviderMapping.get(provider.getId());
479 final StatisticsProvider seriesProvider = statisticsService.getProvider(seriesProviderId)
480 .orElseThrow(() -> new IllegalStateException(
481 "The configured provider " + seriesProviderId + " is not available."));
482
483 SeriesSearchQuery query = (SeriesSearchQuery) new SeriesSearchQuery(securityService.getOrganization().getId(),
484 securityService.getUser()).withLimit(limit).withOffset(offset);
485 for (Map.Entry<String, String> filter: filters.entrySet()) {
486 query = (SeriesSearchQuery) applyFilter(filter.getKey(), filter.getValue(), query);
487 }
488 final SearchResult<Series> result = index.getByQuery(query);
489 boolean first = offset == 0;
490 for (SearchResultItem<Series> currentSeries : result.getItems()) {
491 final TimeSeries dataEvent = statisticsService.getTimeSeriesData(seriesProvider,
492 currentSeries.getSource().getIdentifier(), from, to, dataResolution, zoneId);
493 if (fullMetadata) {
494 this.printFullSeriesData(printer, dataEvent, dataResolution,
495 currentSeries.getSource().getIdentifier(), zoneId, first);
496 } else {
497 printData(printer, dataEvent, dataResolution, currentSeries.getSource().getIdentifier(),
498 currentSeries.getSource().getTitle(), zoneId, first);
499 }
500 first = false;
501 }
502 }
503
504
505 private static void printData(
506 CSVPrinter printer,
507 TimeSeries data,
508 DataResolution dataResolution,
509 String resourceId,
510 String title,
511 ZoneId zoneId,
512 boolean printHeader) throws IOException {
513 if (printHeader) {
514 printer.printRecord(header);
515 }
516 for (int i = 0; i < data.getLabels().size(); i++) {
517 printer.printRecord(
518 resourceId,
519 title,
520 formatDate(data.getLabels().get(i), dataResolution, zoneId),
521 data.getValues().get(i)
522 );
523 }
524 }
525
526 private static void printFullData(
527 CSVPrinter printer,
528 TimeSeries data,
529 DataResolution dataResolution,
530 String resourceId,
531 ZoneId zoneId,
532 List<MetadataField> mdfs) throws IOException {
533 for (int i = 0; i < data.getLabels().size(); i++) {
534 List<Object> values = new ArrayList<>();
535 values.add(resourceId);
536 values.addAll(mdfs.stream().map(f -> f.getValue() == null ? "" : f.getValue()).collect(Collectors.toList()));
537 values.add(formatDate(data.getLabels().get(i), dataResolution, zoneId));
538 values.add(data.getValues().get(i));
539 printer.printRecord(values.toArray());
540 }
541 }
542
543 private void printFullEventData(
544 CSVPrinter printer,
545 TimeSeries data,
546 DataResolution dataResolution,
547 String resourceId,
548 ZoneId zoneId,
549 boolean printHeader) throws IOException {
550 final List<MetadataField> mdfs = getEventMetadata(resourceId);
551 if (printHeader) {
552 printer.printRecord(getFullHeader(mdfs));
553 }
554 printFullData(printer, data, dataResolution, resourceId, zoneId, mdfs);
555 }
556
557 private void printFullSeriesData(
558 CSVPrinter printer,
559 TimeSeries data,
560 DataResolution dataResolution,
561 String resourceId,
562 ZoneId zoneId,
563 boolean printHeader) throws IOException {
564 final List<MetadataField> mdfs = getSeriesMetadata(resourceId);
565 if (printHeader) {
566 printer.printRecord(getFullHeader(mdfs));
567 }
568 printFullData(printer, data, dataResolution, resourceId, zoneId, mdfs);
569 }
570
571 private static List<String> getFullHeader(List<MetadataField> mdfs) {
572 final List<String> header = new ArrayList<>();
573 header.add("ID");
574 header.addAll(mdfs.stream().map(MetadataField::getInputID).collect(Collectors.toList()));
575 header.add("Date");
576 header.add("Value");
577 return header;
578 }
579
580 private List<MetadataField> getSeriesMetadata(String resourceId) {
581 List<DublinCoreMetadataCollection> mdcs = this.indexService.getSeriesCatalogUIAdapters()
582 .stream()
583 .filter(a -> !a.equals(this.indexService.getCommonSeriesCatalogUIAdapter()))
584 .filter(a -> !a.getFlavor().equals(this.indexService.getCommonSeriesCatalogUIAdapter().getFlavor()))
585 .map(adapter -> adapter.getFields(resourceId))
586 .flatMap(opt -> opt.map(Stream::of).orElseGet(Stream::empty))
587 .collect(Collectors.toList());
588 if (this.indexService.getCommonSeriesCatalogUIAdapter().getFields(resourceId).isPresent()) {
589 mdcs.add(0, this.indexService.getCommonSeriesCatalogUIAdapter().getFields(resourceId).get());
590 }
591 return mdcs.stream()
592 .map(DublinCoreMetadataCollection::getFields)
593 .flatMap(Collection::stream)
594 .collect(Collectors.toList());
595 }
596
597 private List<MetadataField> getEventMetadata(String resourceId) {
598 final Optional<MediaPackage> optMp = this.assetManager.getMediaPackage(resourceId);
599 if (optMp.isEmpty()) {
600 return Collections.emptyList();
601 }
602 final List<DublinCoreMetadataCollection> mdcs = this.indexService.getEventCatalogUIAdapters()
603 .stream()
604 .filter(a -> !a.equals(this.indexService.getCommonEventCatalogUIAdapter()))
605 .filter(a -> !a.getFlavor().equals(this.indexService.getCommonEventCatalogUIAdapter().getFlavor()))
606 .map(adapter -> adapter.getFields(optMp.get()))
607 .collect(Collectors.toList());
608 mdcs.add(0, this.indexService.getCommonEventCatalogUIAdapter().getFields(optMp.get()));
609 return mdcs.stream()
610 .map(DublinCoreMetadataCollection::getFields)
611 .flatMap(Collection::stream)
612 .collect(Collectors.toList());
613 }
614
615 private static SearchQuery applyFilter(final String name, final String value, final EventSearchQuery query) {
616 if ("presenters".equals(name)) {
617 return query.withPresenter(value);
618 } else if ("creator".equals(name)) {
619 return query.withCreator(value);
620 } else if ("contributors".equals(name)) {
621 return query.withContributor(value);
622 } else if ("location".equals(name)) {
623 return query.withLocation(value);
624 } else if ("textFilter".equals(name)) {
625 return query.withText("*" + value + "*");
626 } else if ("series".equals(name)) {
627 return query.withSeriesId(value);
628 } else if ("subject".equals(name)) {
629 return query.withSubject(value);
630 } else if ("title".equals(name)) {
631 return query.withTitle(value);
632 } else if ("description".equals(name)) {
633 return query.withDescription(value);
634 } else if ("series_name".equals(name)) {
635 return query.withSeriesName(value);
636 } else if ("language".equals(name)) {
637 return query.withLanguage(value);
638 } else if ("created".equals(name)) {
639 return query.withCreated(value);
640 } else if ("license".equals(name)) {
641 return query.withLicense(value);
642 } else if ("rightsholder".equals(name)) {
643 return query.withRights(value);
644 } else if ("is_part_of".equals(name)) {
645 return query.withSeriesId(value);
646 } else if ("source".equals(name)) {
647 return query.withSource(value);
648 } else if ("status".equals(name)) {
649 return query.withEventStatus(value);
650 } else if ("agent_id".equals(name)) {
651 return query.withAgentId(value);
652 } else if ("publisher".equals(name)) {
653 return query.withPublisher(value);
654 } else {
655 throw new IllegalArgumentException("Unknown filter :" + name);
656 }
657 }
658
659 private static SearchQuery applyFilter(final String name, final String value, final SeriesSearchQuery query) {
660 if ("contributors".equals(name)) {
661 return query.withContributor(value);
662 } else if ("creator".equals(name)) {
663 return query.withCreator(value);
664 } else if ("textFilter".equals(name)) {
665 return query.withText("*" + value + "*");
666 } else if ("subject".equals(name)) {
667 return query.withSubject(value);
668 } else if ("title".equals(name)) {
669 return query.withTitle(value);
670 } else if ("description".equals(name)) {
671 return query.withDescription(value);
672 } else if ("language".equals(name)) {
673 return query.withLanguage(value);
674 } else if ("license".equals(name)) {
675 return query.withLicense(value);
676 } else if ("publisher".equals(name)) {
677 return query.withPublisher(value);
678 } else if ("organizer".equals(name)) {
679 return query.withOrganizer(value);
680 } else if ("rightsholder".equals(name)) {
681 return query.withRightsHolder(value);
682 } else {
683 throw new IllegalArgumentException("Unknown filter :" + name);
684 }
685 }
686
687 }