View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  package org.opencastproject.elasticsearch.index.objects.series;
22  
23  import static org.opencastproject.security.api.SecurityConstants.GLOBAL_ADMIN_ROLE;
24  
25  import org.opencastproject.elasticsearch.api.SearchTerms;
26  import org.opencastproject.elasticsearch.impl.AbstractSearchQuery;
27  import org.opencastproject.elasticsearch.impl.IndexSchema;
28  import org.opencastproject.security.api.Permissions;
29  import org.opencastproject.security.api.Permissions.Action;
30  import org.opencastproject.security.api.User;
31  import org.opencastproject.util.requests.SortCriterion.Order;
32  
33  import org.apache.commons.lang3.StringUtils;
34  
35  import java.util.ArrayList;
36  import java.util.Date;
37  import java.util.HashSet;
38  import java.util.List;
39  import java.util.Map;
40  import java.util.Set;
41  
42  /**
43   * This interface defines a fluent api for a query object used to lookup series in the search index.
44   */
45  public class SeriesSearchQuery extends AbstractSearchQuery {
46  
47    protected List<String> identifiers = new ArrayList<String>();
48    private String title = null;
49    private User user = null;
50    private String description = null;
51    private final Set<String> actions = new HashSet<String>();
52    private final List<String> subjects = new ArrayList<String>();
53    private String organization = null;
54    private String language = null;
55    private String creator = null;
56    private String license = null;
57    private String accessPolicy = null;
58    private String managedAcl = null;
59    private final List<String> organizers = new ArrayList<String>();
60    private final List<String> contributors = new ArrayList<String>();
61    private final List<String> publishers = new ArrayList<String>();
62    private Date createdFrom = null;
63    private Date createdTo = null;
64    private boolean editOnly = false;
65    private String rightsHolder = null;
66    private Long theme = null;
67  
68    private static final Map<String, String> SORT_FIELDS = Map.of(
69        SeriesIndexSchema.TITLE, SeriesIndexSchema.TITLE.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION),
70        SeriesIndexSchema.DESCRIPTION, SeriesIndexSchema.DESCRIPTION.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION),
71        SeriesIndexSchema.SUBJECT, SeriesIndexSchema.SUBJECT.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION),
72        SeriesIndexSchema.CREATOR, SeriesIndexSchema.CREATOR.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION),
73        SeriesIndexSchema.ORGANIZERS, SeriesIndexSchema.ORGANIZERS.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION),
74        SeriesIndexSchema.CONTRIBUTORS, SeriesIndexSchema.CONTRIBUTORS.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION),
75        SeriesIndexSchema.PUBLISHERS, SeriesIndexSchema.PUBLISHERS.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION),
76        SeriesIndexSchema.RIGHTS_HOLDER, SeriesIndexSchema.RIGHTS_HOLDER.concat(IndexSchema.SORT_FIELD_NAME_EXTENSION)
77    );
78  
79    @SuppressWarnings("unused")
80    private SeriesSearchQuery() {
81    }
82  
83    @Override
84    protected String sortOrderFieldName(String field) {
85      if (SORT_FIELDS.containsKey(field)) {
86        return SORT_FIELDS.get(field);
87      }
88      return field;
89    }
90  
91    /**
92     * Creates a query that will return series documents.
93     */
94    public SeriesSearchQuery(String organization, User user) {
95      super(Series.DOCUMENT_TYPE);
96      this.organization = organization;
97      this.user = user;
98      this.actions.add(Permissions.Action.READ.toString());
99      if (!user.hasRole(GLOBAL_ADMIN_ROLE)) {
100       if (!user.getOrganization().getId().equals(organization)) {
101         throw new IllegalStateException("User's organization must match search organization");
102       }
103     }
104   }
105 
106   /**
107    * Selects series with the given identifier.
108    * <p>
109    * Note that this method may be called multiple times to support selection of multiple series.
110    *
111    * @param id
112    *          the series identifier
113    * @return the enhanced search query
114    */
115   public SeriesSearchQuery withIdentifier(String id) {
116     if (StringUtils.isBlank(id)) {
117       throw new IllegalArgumentException("Identifier cannot be null");
118     }
119     this.identifiers.add(id);
120     return this;
121   }
122 
123   /**
124    * Returns the list of series identifiers or an empty array if no identifiers have been specified.
125    *
126    * @return the identifiers
127    */
128   public String[] getIdentifier() {
129     return identifiers.toArray(new String[identifiers.size()]);
130   }
131 
132   /**
133    * Selects series with the given title.
134    *
135    * @param title
136    *          the title
137    * @return the enhanced search query
138    */
139   public SeriesSearchQuery withTitle(String title) {
140     this.title = title;
141     return this;
142   }
143 
144   /**
145    * Returns the title of the series.
146    *
147    * @return the title
148    */
149   public String getTitle() {
150     return title;
151   }
152 
153   /**
154    * Filter the series without any action checked.
155    *
156    * @return the enhanced search query
157    */
158   public SeriesSearchQuery withoutActions() {
159     this.actions.clear();
160     return this;
161   }
162 
163   /**
164    * Filter the series with the given action.
165    * <p>
166    * Note that this method may be called multiple times to support filtering by multiple actions.
167    *
168    * @param action
169    *          the action
170    * @return the enhanced search query
171    */
172   public SeriesSearchQuery withAction(Action action) {
173     if (action == null) {
174       throw new IllegalArgumentException("Action cannot be null");
175     }
176     this.actions.add(action.toString());
177     return this;
178   }
179 
180   /**
181    * Returns the list of actions or an empty array if no actions have been specified.
182    *
183    * @return the actions
184    */
185   public String[] getActions() {
186     return actions.toArray(new String[actions.size()]);
187   }
188 
189   /**
190    * Selects series with the given description.
191    *
192    * @param description
193    *          the description
194    * @return the enhanced search query
195    */
196   public SeriesSearchQuery withDescription(String description) {
197     this.description = description;
198     return this;
199   }
200 
201   /**
202    * Returns the description of the series.
203    *
204    * @return the description
205    */
206   public String getDescription() {
207     return description;
208   }
209 
210   /**
211    * Selects series with the given subject.
212    * <p>
213    * Note that this method may be called multiple times to support selection of multiple series.
214    *
215    * @param subject
216    *          the subject
217    * @return the enhanced search query
218    */
219   public SeriesSearchQuery withSubject(String subject) {
220     if (StringUtils.isBlank(subject)) {
221       throw new IllegalArgumentException("Subject cannot be null");
222     }
223     this.subjects.add(subject);
224     return this;
225   }
226 
227   /**
228    * Returns the list of recording subjects or an empty array if no subject have been specified.
229    *
230    * @return the subjects
231    */
232   public String[] getSubjects() {
233     return subjects.toArray(new String[subjects.size()]);
234   }
235 
236   /**
237    * Returns the organization of the series.
238    *
239    * @return the organization
240    */
241   public String getOrganization() {
242     return organization;
243   }
244 
245   /**
246    * Returns the user of this search query
247    *
248    * @return the user of this search query
249    */
250   public User getUser() {
251     return user;
252   }
253 
254   /**
255    * Selects series with the given language.
256    *
257    * @param language
258    *          the language
259    * @return the enhanced search query
260    */
261   public SeriesSearchQuery withLanguage(String language) {
262     this.language = language;
263     return this;
264   }
265 
266   /**
267    * Returns the language of the series.
268    *
269    * @return the language
270    */
271   public String getLanguage() {
272     return language;
273   }
274 
275   /**
276    * Selects series with the given creator.
277    *
278    * @param creator
279    *          the creator
280    * @return the enhanced search query
281    */
282   public SeriesSearchQuery withCreator(String creator) {
283     this.creator = creator;
284     return this;
285   }
286 
287   /**
288    * Returns the creator of the series.
289    *
290    * @return the creator
291    */
292   public String getCreator() {
293     return creator;
294   }
295 
296   /**
297    * Selects series with the given license.
298    *
299    * @param license
300    *          the license
301    * @return the enhanced search query
302    */
303   public SeriesSearchQuery withLicense(String license) {
304     this.license = license;
305     return this;
306   }
307 
308   /**
309    * Returns the license of the series.
310    *
311    * @return the license
312    */
313   public String getLicense() {
314     return license;
315   }
316 
317   /**
318    * Selects series with the given access policy.
319    *
320    * @param accessPolicy
321    *          the access policy
322    * @return the enhanced search query
323    */
324   public SeriesSearchQuery withAccessPolicy(String accessPolicy) {
325     this.accessPolicy = accessPolicy;
326     return this;
327   }
328 
329   /**
330    * Returns the access policy of the series.
331    *
332    * @return the access policy
333    */
334   public String getAccessPolicy() {
335     return accessPolicy;
336   }
337 
338   /**
339    * Selects series with the given theme.
340    *
341    * @param theme
342    *          the theme
343    * @return the enhanced search query
344    */
345   public SeriesSearchQuery withTheme(long theme) {
346     this.theme = theme;
347     return this;
348   }
349 
350   /**
351    * Returns the theme of the series.
352    *
353    * @return the theme
354    */
355   public Long getTheme() {
356     return theme;
357   }
358 
359   /**
360    * Selects series with the given managed ACL name.
361    *
362    * @param managedAcl
363    *          the name of the managed ACL
364    * @return the enhanced search query
365    */
366   public SeriesSearchQuery withManagedAcl(String managedAcl) {
367     this.managedAcl = managedAcl;
368     return this;
369   }
370 
371   /**
372    * Returns the name of the managed ACL set to the series.
373    *
374    * @return the name of the managed ACL
375    */
376   public String getManagedAcl() {
377     return managedAcl;
378   }
379 
380   /**
381    * Selects series with the given organizers.
382    * <p>
383    * Note that this method may be called multiple times to support selection of multiple series.
384    *
385    * @param organizer
386    *          the organizer
387    * @return the enhanced search query
388    */
389   public SeriesSearchQuery withOrganizer(String organizer) {
390     if (StringUtils.isBlank(organizer)) {
391       throw new IllegalArgumentException("Organizer cannot be null");
392     }
393     this.organizers.add(organizer);
394     return this;
395   }
396 
397   /**
398    * Returns the list of series organizers or an empty array if no organizers have been specified.
399    *
400    * @return the organizers
401    */
402   public String[] getOrganizers() {
403     return organizers.toArray(new String[organizers.size()]);
404   }
405 
406   /**
407    * Selects series with the given contributor.
408    * <p>
409    * Note that this method may be called multiple times to support selection of multiple contributors.
410    *
411    * @param contributor
412    *          the contributor
413    * @return the enhanced search query
414    */
415   public SeriesSearchQuery withContributor(String contributor) {
416     if (StringUtils.isBlank(contributor)) {
417       throw new IllegalArgumentException("Contributor can't be null");
418     }
419     this.contributors.add(contributor);
420     return this;
421   }
422 
423   /**
424    * Returns the list of series contributors or an empty array if no contributor have been specified.
425    *
426    * @return the contributors
427    */
428   public String[] getContributors() {
429     return contributors.toArray(new String[contributors.size()]);
430   }
431 
432   /**
433    * Select series with the given publishers
434    *
435    * @param publisher
436    *          The publisher to add to the search query.
437    * @return This query with the added publisher
438    */
439   public SeriesSearchQuery withPublisher(String publisher) {
440     if (StringUtils.isBlank(publisher)) {
441       throw new IllegalArgumentException("Publisher can't be null");
442     }
443     this.publishers.add(publisher);
444     return this;
445   }
446 
447   /**
448    * Returns an array of series publishers or an empty array if no publisher has been specified.
449    *
450    * @return The publishers
451    */
452   public String[] getPublishers() {
453     return publishers.toArray(new String[publishers.size()]);
454   }
455 
456   /**
457    * The created date to start looking for series.
458    *
459    * @param createdFrom
460    *          The created date to start looking for series
461    * @return the enhanced search query
462    */
463   public SeriesSearchQuery withCreatedFrom(Date createdFrom) {
464     this.createdFrom = createdFrom;
465     return this;
466   }
467 
468   /**
469    * @return The Date after which all series returned should have been created
470    */
471   public Date getCreatedFrom() {
472     return createdFrom;
473   }
474 
475   /**
476    * The created date to stop looking for series.
477    *
478    * @param createdTo
479    *          The created date to stop looking for series
480    * @return the enhanced search query
481    */
482   public SeriesSearchQuery withCreatedTo(Date createdTo) {
483     this.createdTo = createdTo;
484     return this;
485   }
486 
487   /**
488    * @return The Date before which all series returned should have been created
489    */
490   public Date getCreatedTo() {
491     return createdTo;
492   }
493 
494   /**
495    * @param edit
496    *          True to only get series with edit permissions
497    * @return enhanced search query
498    */
499   public SeriesSearchQuery withEdit(Boolean edit) {
500     this.editOnly = edit;
501     return this;
502   }
503 
504   /**
505    * @return True to only get series that this user can edit.
506    */
507   public boolean isEditOnly() {
508     return editOnly;
509   }
510 
511   /**
512    * @param rightsHolder
513    *          The rights holder to search for
514    * @return enhanced query
515    */
516   public SeriesSearchQuery withRightsHolder(String rightsHolder) {
517     this.rightsHolder = rightsHolder;
518     return this;
519   }
520 
521   /**
522    * @return The rights holder to search for
523    */
524   public String getRightsHolder() {
525     return rightsHolder;
526   }
527 
528   /**
529    * Defines the sort order for the series by contributors.
530    *
531    * @param order
532    *          the order
533    * @return the enhanced search query
534    */
535   public SeriesSearchQuery sortByIdentifer(Order order) {
536     withSortOrder(SeriesIndexSchema.UID, order);
537     return this;
538   }
539 
540   /**
541    * Returns the sort order for the series created date.
542    *
543    * @return the sort order
544    */
545   public Order getSeriesIdentifierSortOrder() {
546     return getSortOrder(SeriesIndexSchema.UID);
547   }
548 
549   /**
550    * Defines the sort order for the series by contributors.
551    *
552    * @param order
553    *          the order
554    * @return the enhanced search query
555    */
556   public SeriesSearchQuery sortBySubject(Order order) {
557     withSortOrder(SeriesIndexSchema.SUBJECT, order);
558     return this;
559   }
560 
561   /**
562    * Returns the sort order for the series created date.
563    *
564    * @return the sort order
565    */
566   public Order getSeriesSubjectSortOrder() {
567     return getSortOrder(SeriesIndexSchema.SUBJECT);
568   }
569 
570   /**
571    * Defines the sort order for the series by contributors.
572    *
573    * @param order
574    *          the order
575    * @return the enhanced search query
576    */
577   public SeriesSearchQuery sortByCreator(Order order) {
578     withSortOrder(SeriesIndexSchema.CREATOR, order);
579     return this;
580   }
581 
582   /**
583    * Returns the sort order for the series created date.
584    *
585    * @return the sort order
586    */
587   public Order getSeriesCreatorSortOrder() {
588     return getSortOrder(SeriesIndexSchema.CREATOR);
589   }
590 
591   /**
592    * Defines the sort order for the series by contributors.
593    *
594    * @param order
595    *          the order
596    * @return the enhanced search query
597    */
598   public SeriesSearchQuery sortByPublishers(Order order) {
599     withSortOrder(SeriesIndexSchema.PUBLISHERS, order);
600     return this;
601   }
602 
603   /**
604    * Returns the sort order for the series created date.
605    *
606    * @return the sort order
607    */
608   public Order getSeriesPublishersSortOrder() {
609     return getSortOrder(SeriesIndexSchema.PUBLISHERS);
610   }
611 
612   /**
613    * Defines the sort order for the series by contributors.
614    *
615    * @param order
616    *          the order
617    * @return the enhanced search query
618    */
619   public SeriesSearchQuery sortByDescription(Order order) {
620     withSortOrder(SeriesIndexSchema.DESCRIPTION, order);
621     return this;
622   }
623 
624   /**
625    * Returns the sort order for the series created date.
626    *
627    * @return the sort order
628    */
629   public Order getSeriesDescriptionSortOrder() {
630     return getSortOrder(SeriesIndexSchema.DESCRIPTION);
631   }
632 
633   /**
634    * Defines the sort order for the series by contributors.
635    *
636    * @param order
637    *          the order
638    * @return the enhanced search query
639    */
640   public SeriesSearchQuery sortByLanguage(Order order) {
641     withSortOrder(SeriesIndexSchema.LANGUAGE, order);
642     return this;
643   }
644 
645   /**
646    * Returns the sort order for the series created date.
647    *
648    * @return the sort order
649    */
650   public Order getSeriesLanguageSortOrder() {
651     return getSortOrder(SeriesIndexSchema.LANGUAGE);
652   }
653 
654   /**
655    * Defines the sort order for the series by contributors.
656    *
657    * @param order
658    *          the order
659    * @return the enhanced search query
660    */
661   public SeriesSearchQuery sortByRightsHolder(Order order) {
662     withSortOrder(SeriesIndexSchema.RIGHTS_HOLDER, order);
663     return this;
664   }
665 
666   /**
667    * Returns the sort order for the series created date.
668    *
669    * @return the sort order
670    */
671   public Order getSeriesRightsHolderSortOrder() {
672     return getSortOrder(SeriesIndexSchema.RIGHTS_HOLDER);
673   }
674 
675   /**
676    * Defines the sort order for the series by contributors.
677    *
678    * @param order
679    *          the order
680    * @return the enhanced search query
681    */
682   public SeriesSearchQuery sortByLicense(Order order) {
683     withSortOrder(SeriesIndexSchema.LICENSE, order);
684     return this;
685   }
686 
687   /**
688    * Returns the sort order for the series created date.
689    *
690    * @return the sort order
691    */
692   public Order getSeriesLicenseSortOrder() {
693     return getSortOrder(SeriesIndexSchema.LICENSE);
694   }
695 
696   /**
697    * Defines the sort order for the series by contributors.
698    *
699    * @param order
700    *          the order
701    * @return the enhanced search query
702    */
703   public SeriesSearchQuery sortByContributors(Order order) {
704     withSortOrder(SeriesIndexSchema.CONTRIBUTORS, order);
705     return this;
706   }
707 
708   /**
709    * Returns the sort order for the series created date.
710    *
711    * @return the sort order
712    */
713   public Order getSeriesContributorsSortOrder() {
714     return getSortOrder(SeriesIndexSchema.CONTRIBUTORS);
715   }
716 
717   /**
718    * Defines the sort order for the managed ACL.
719    *
720    * @param order
721    *          the order
722    * @return the enhanced search query
723    */
724   public SeriesSearchQuery sortByManagedAcl(Order order) {
725     withSortOrder(SeriesIndexSchema.MANAGED_ACL, order);
726     return this;
727   }
728 
729   /**
730    * Returns the sort order for the series managed ACL.
731    *
732    * @return the sort order
733    */
734   public Order getSeriesManagedAclSortOrder() {
735     return getSortOrder(SeriesIndexSchema.MANAGED_ACL);
736   }
737 
738   /**
739    * Defines the sort order for the series created date &amp; time.
740    *
741    * @param order
742    *          the order
743    * @return the enhanced search query
744    */
745   public SeriesSearchQuery sortByCreatedDateTime(Order order) {
746     withSortOrder(SeriesIndexSchema.CREATED_DATE_TIME, order);
747     return this;
748   }
749 
750   /**
751    * Returns the sort order for the series created date.
752    *
753    * @return the sort order
754    */
755   public Order getSeriesDateSortOrder() {
756     return getSortOrder(SeriesIndexSchema.CREATED_DATE_TIME);
757   }
758 
759   /**
760    * Defines the sort order for the series by organizers.
761    *
762    * @param order
763    *          the order
764    * @return the enhanced search query
765    */
766   public SeriesSearchQuery sortByOrganizers(Order order) {
767     withSortOrder(SeriesIndexSchema.ORGANIZERS, order);
768     return this;
769   }
770 
771   /**
772    * Returns the sort order for the series organizers.
773    *
774    * @return the sort order
775    */
776   public Order getSeriesOrganizersSortOrder() {
777     return getSortOrder(SeriesIndexSchema.ORGANIZERS);
778   }
779 
780   /**
781    * Defines the sort order for the series by title.
782    *
783    * @param order
784    *          the order
785    * @return the enhanced search query
786    */
787   public SeriesSearchQuery sortByTitle(Order order) {
788     withSortOrder(SeriesIndexSchema.TITLE, order);
789     return this;
790   }
791 
792   /**
793    * Returns the sort order for the series title.
794    *
795    * @return the sort order
796    */
797   public Order getSeriesTitleSortOrder() {
798     return getSortOrder(SeriesIndexSchema.TITLE);
799   }
800 
801   @Override
802   public String toString() {
803     StringBuilder sb = new StringBuilder();
804     sb.append(SeriesSearchQuery.class.getSimpleName() + " ");
805     if (identifiers.size() > 0) {
806       sb.append("ids:'" + identifiers.toString() + "' ");
807     }
808     if (StringUtils.trimToNull(title) != null) {
809       sb.append("title:'" + title + "' ");
810     }
811     if (StringUtils.trimToNull(description) != null) {
812       sb.append("description:'" + description + "' ");
813     }
814     if (subjects.size() > 0) {
815       sb.append("subjects:'" + subjects.toString() + "' ");
816     }
817     if (StringUtils.trimToNull(organization) != null) {
818       sb.append("organization:'" + organization + "' ");
819     }
820     if (StringUtils.trimToNull(language) != null) {
821       sb.append("language:'" + language + "' ");
822     }
823     if (StringUtils.trimToNull(creator) != null) {
824       sb.append("creator:'" + creator + "' ");
825     }
826     if (StringUtils.trimToNull(license) != null) {
827       sb.append("license:'" + license + "' ");
828     }
829     if (StringUtils.trimToNull(accessPolicy) != null) {
830       sb.append("ACL:'" + accessPolicy + "' ");
831     }
832 
833     if (createdFrom != null) {
834       sb.append("Created From:'" + createdFrom + "' ");
835     }
836 
837     if (createdTo != null) {
838       sb.append("Created To:'" + createdTo + "' ");
839     }
840 
841     if (organizers.size() > 0) {
842       sb.append("organizers:'" + organizers.toString() + "' ");
843     }
844 
845     if (contributors.size() > 0) {
846       sb.append("contributors:'" + contributors.toString() + "' ");
847     }
848 
849     if (publishers.size() > 0) {
850       sb.append("publishers:'" + publishers.toString() + "' ");
851     }
852 
853     if (theme != null) {
854       sb.append("Theme:'" + theme + "' ");
855     }
856 
857     sb.append("Edit:'" + editOnly + "' ");
858 
859     if (getTerms().size() > 0) {
860       sb.append("Text:");
861       for (SearchTerms<String> searchTerm : getTerms()) {
862         sb.append("'" + searchTerm.getTerms() + "' ");
863       }
864     }
865 
866     if (StringUtils.trimToNull(rightsHolder) != null) {
867       sb.append("Rights Holder:'" + rightsHolder + "' ");
868     }
869 
870     return sb.toString();
871 
872   }
873 
874 }