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