/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.index.service.impl.index.event;
import static org.opencastproject.index.service.util.ListProviderUtil.splitStringList;
import org.opencastproject.index.service.impl.index.AbstractSearchIndex;
import org.opencastproject.index.service.impl.index.series.Series;
import org.opencastproject.index.service.impl.index.series.SeriesSearchQuery;
import org.opencastproject.matterhorn.search.SearchIndexException;
import org.opencastproject.matterhorn.search.SearchMetadata;
import org.opencastproject.matterhorn.search.SearchResult;
import org.opencastproject.matterhorn.search.SearchResultItem;
import org.opencastproject.matterhorn.search.impl.SearchMetadataCollection;
import org.opencastproject.mediapackage.Attachment;
import org.opencastproject.mediapackage.Catalog;
import org.opencastproject.mediapackage.MediaPackage;
import org.opencastproject.mediapackage.Publication;
import org.opencastproject.mediapackage.Track;
import org.opencastproject.mediapackage.TrackSupport;
import org.opencastproject.mediapackage.VideoStream;
import org.opencastproject.metadata.dublincore.DCMIPeriod;
import org.opencastproject.metadata.dublincore.DublinCore;
import org.opencastproject.metadata.dublincore.EncodingSchemeUtils;
import org.opencastproject.security.api.AccessControlEntry;
import org.opencastproject.security.api.AccessControlList;
import org.opencastproject.security.api.AccessControlParser;
import org.opencastproject.security.api.Permissions;
import org.opencastproject.security.api.Permissions.Action;
import org.opencastproject.security.api.User;
import org.opencastproject.util.DateTimeSupport;
import org.opencastproject.util.NotFoundException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Utility implementation to deal with the conversion of recording events and its corresponding index data structures.
*/
public final class EventIndexUtils {
private static final Logger logger = LoggerFactory.getLogger(EventIndexUtils.class);
// The number of attempts to get the series title in case it hasn't been added to the index.
public static final int DEFAULT_ATTEMPTS = 10;
// The amount of time in ms to wait before trying to get the series title again.
public static final long DEFAULT_SLEEP = 100L;
/**
* This is a utility class and should therefore not be instantiated.
*/
private EventIndexUtils() {
}
/**
* Creates a search result item based on the data returned from the search index.
*
* @param metadata
* the search metadata
* @return the search result item
* @throws IOException
* if unmarshalling fails
*/
public static Event toRecordingEvent(SearchMetadataCollection metadata) throws IOException {
Map<String, SearchMetadata<?>> metadataMap = metadata.toMap();
String eventJson = (String) metadataMap.get(EventIndexSchema.OBJECT).getValue();
return Event.valueOf(IOUtils.toInputStream(eventJson));
}
/**
* Creates search metadata from a recording event such that the event can be stored in the search index.
*
* @param event
* the recording event
* @return the set of metadata
*/
public static SearchMetadataCollection toSearchMetadata(Event event) {
SearchMetadataCollection metadata = new SearchMetadataCollection(
event.getIdentifier().concat(event.getOrganization()), Event.DOCUMENT_TYPE);
metadata.addField(EventIndexSchema.UID, event.getIdentifier(), true);
metadata.addField(EventIndexSchema.ORGANIZATION, event.getOrganization(), false);
metadata.addField(EventIndexSchema.OBJECT, event.toXML(), false);
if (StringUtils.isNotBlank(event.getTitle()))
metadata.addField(EventIndexSchema.TITLE, event.getTitle(), true);
if (StringUtils.isNotBlank(event.getDescription()))
metadata.addField(EventIndexSchema.DESCRIPTION, event.getDescription(), true);
if (StringUtils.isNotBlank(event.getLocation()))
metadata.addField(EventIndexSchema.LOCATION, event.getLocation(), true);
if (StringUtils.isNotBlank(event.getSeriesId()))
metadata.addField(EventIndexSchema.SERIES_ID, event.getSeriesId(), true);
if (StringUtils.isNotBlank(event.getSeriesName()))
metadata.addField(EventIndexSchema.SERIES_NAME, event.getSeriesName(), true);
if (StringUtils.isNotBlank(event.getLanguage()))
metadata.addField(EventIndexSchema.LANGUAGE, event.getLanguage(), true);
if (StringUtils.isNotBlank(event.getSubject()))
metadata.addField(EventIndexSchema.SUBJECT, event.getSubject(), true);
if (StringUtils.isNotBlank(event.getSource()))
metadata.addField(EventIndexSchema.SOURCE, event.getSource(), true);
if (StringUtils.isNotBlank(event.getCreated()))
metadata.addField(EventIndexSchema.CREATED, event.getCreated(), true);
if (StringUtils.isNotBlank(event.getCreator()))
metadata.addField(EventIndexSchema.CREATOR, event.getCreator(), true);
if (StringUtils.isNotBlank(event.getLicense()))
metadata.addField(EventIndexSchema.LICENSE, event.getLicense(), true);
if (StringUtils.isNotBlank(event.getRights()))
metadata.addField(EventIndexSchema.RIGHTS, event.getRights(), true);
if (StringUtils.isNotBlank(event.getManagedAcl()))
metadata.addField(EventIndexSchema.MANAGED_ACL, event.getManagedAcl(), true);
if (StringUtils.isNotBlank(event.getWorkflowState()))
metadata.addField(EventIndexSchema.WORKFLOW_STATE, event.getWorkflowState(), true);
if (event.getWorkflowId() != null)
metadata.addField(EventIndexSchema.WORKFLOW_ID, event.getWorkflowId(), true);
if (StringUtils.isNotBlank(event.getWorkflowDefinitionId()))
metadata.addField(EventIndexSchema.WORKFLOW_DEFINITION_ID, event.getWorkflowDefinitionId(), true);
if (StringUtils.isNotBlank(event.getRecordingStartDate()))
metadata.addField(EventIndexSchema.START_DATE, event.getRecordingStartDate(), true);
if (StringUtils.isNotBlank(event.getRecordingEndDate()))
metadata.addField(EventIndexSchema.END_DATE, event.getRecordingEndDate(), true);
if (event.getDuration() != null)
metadata.addField(EventIndexSchema.DURATION, event.getDuration(), true);
if (StringUtils.isNotBlank(event.getReviewStatus()))
metadata.addField(EventIndexSchema.REVIEW_STATUS, event.getReviewStatus(), true);
if (StringUtils.isNotBlank(event.getReviewDate()))
metadata.addField(EventIndexSchema.REVIEW_DATE, event.getReviewDate(), true);
if (StringUtils.isNotBlank(event.getWorkflowScheduledDate()))
metadata.addField(EventIndexSchema.WORKFLOW_SCHEDULED_DATETIME, event.getWorkflowScheduledDate(), true);
if (event.getArchiveVersion() != null)
metadata.addField(EventIndexSchema.ARCHIVE_VERSION, event.getArchiveVersion(), true);
if (event.getOptedOut() != null)
metadata.addField(EventIndexSchema.OPTED_OUT, event.getOptedOut(), true);
if (event.getBlacklisted() != null)
metadata.addField(EventIndexSchema.BLACKLISTED, event.getBlacklisted(), true);
if (event.getSchedulingStatus() != null)
metadata.addField(EventIndexSchema.SCHEDULING_STATUS, event.getSchedulingStatus(), true);
if (event.getRecordingStatus() != null)
metadata.addField(EventIndexSchema.RECORDING_STATUS, event.getRecordingStatus(), true);
metadata.addField(EventIndexSchema.EVENT_STATUS, event.getEventStatus(), true);
metadata.addField(EventIndexSchema.HAS_COMMENTS, event.hasComments(), true);
metadata.addField(EventIndexSchema.HAS_OPEN_COMMENTS, event.hasOpenComments(), true);
metadata.addField(EventIndexSchema.NEEDS_CUTTING, event.needsCutting(), true);
if (event.getPublications() != null) {
List<Publication> publications = event.getPublications();
HashMap<String, Object>[] publicationsArray = new HashMap[publications.size()];
for (int i = 0; i < publications.size(); i++)
publicationsArray[i] = generatePublicationDoc(publications.get(i));
metadata.addField(EventIndexSchema.PUBLICATION, publicationsArray, true);
}
if (event.getPresenters() != null) {
List<String> presenters = event.getPresenters();
metadata.addField(EventIndexSchema.PRESENTER, presenters.toArray(new String[presenters.size()]), true);
}
if (event.getContributors() != null) {
List<String> contributors = event.getContributors();
metadata.addField(EventIndexSchema.CONTRIBUTOR, contributors.toArray(new String[contributors.size()]), true);
}
if (event.getTrackMimetypes() != null) {
List<String> trackMimetypes = event.getTrackMimetypes();
metadata.addField(EventIndexSchema.TRACK_MIMETYPE, trackMimetypes.toArray(new String[trackMimetypes.size()]),
true);
}
if (event.getTrackStreamResolution() != null) {
List<String> trackStreamResolutions = event.getTrackStreamResolution();
metadata.addField(EventIndexSchema.TRACK_STREAM_RESOLUTION,
trackStreamResolutions.toArray(new String[trackStreamResolutions.size()]), true);
}
if (event.getTrackFlavors() != null) {
List<String> trackFlavors = event.getTrackFlavors();
metadata.addField(EventIndexSchema.TRACK_FLAVOR, trackFlavors.toArray(new String[trackFlavors.size()]), true);
}
if (event.getMetadataFlavors() != null) {
List<String> metadataFlavors = event.getMetadataFlavors();
metadata.addField(EventIndexSchema.METADATA_FLAVOR, metadataFlavors.toArray(new String[metadataFlavors.size()]),
true);
}
if (event.getMetadataMimetypes() != null) {
List<String> metadataMimetypes = event.getMetadataMimetypes();
metadata.addField(EventIndexSchema.METADATA_MIMETYPE,
metadataMimetypes.toArray(new String[metadataMimetypes.size()]), true);
}
if (event.getAttachmentFlavors() != null) {
List<String> attachmentFlavors = event.getAttachmentFlavors();
metadata.addField(EventIndexSchema.ATTACHMENT_FLAVOR,
attachmentFlavors.toArray(new String[attachmentFlavors.size()]), true);
}
if (StringUtils.isNotBlank(event.getAccessPolicy())) {
metadata.addField(EventIndexSchema.ACCESS_POLICY, event.getAccessPolicy(), true);
addAuthorization(metadata, event.getAccessPolicy());
}
if (StringUtils.isNotBlank(event.getAgentId())) {
metadata.addField(EventIndexSchema.AGENT_ID, event.getAgentId(), true);
}
if (StringUtils.isNotBlank(event.getTechnicalStartTime())) {
metadata.addField(EventIndexSchema.TECHNICAL_START, event.getTechnicalStartTime(), true);
}
if (StringUtils.isNotBlank(event.getTechnicalEndTime())) {
metadata.addField(EventIndexSchema.TECHNICAL_END, event.getTechnicalEndTime(), true);
}
if (event.getTechnicalPresenters() != null) {
metadata.addField(EventIndexSchema.TECHNICAL_PRESENTERS,
event.getTechnicalPresenters().toArray(new String[event.getTechnicalPresenters().size()]), true);
}
if (event.getAgentConfiguration() != null) {
metadata.addField(EventIndexSchema.AGENT_CONFIGURATION, event.getAgentConfiguration(), false);
}
return metadata;
}
private static void addObjectStringtToMap(HashMap<String, Object> map, String key, Object value) {
if (value == null) {
map.put(key, "");
} else {
map.put(key, value.toString());
}
}
/**
* Generate the document structure for the publication element
*
* @param publication
* the source publication element
* @return a map representing the ES document structure of the publication element
*/
private static HashMap<String, Object> generatePublicationDoc(Publication publication) {
HashMap<String, Object> pMap = new HashMap<String, Object>();
// Add first level elements
pMap.put(PublicationIndexSchema.CHANNEL, publication.getChannel());
addObjectStringtToMap(pMap, PublicationIndexSchema.MIMETYPE, publication.getMimeType());
// Attachments
Attachment[] attachments = publication.getAttachments();
HashMap<String, Object>[] attachmentsArray = new HashMap[attachments.length];
for (int i = 0; i < attachmentsArray.length; i++) {
Attachment attachment = attachments[i];
HashMap<String, Object> element = new HashMap<String, Object>();
element.put(PublicationIndexSchema.ELEMENT_ID, attachment.getIdentifier());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_MIMETYPE, attachment.getMimeType());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_TYPE, attachment.getElementType());
element.put(PublicationIndexSchema.ELEMENT_TAG, attachment.getTags());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_URL, attachment.getURI());
element.put(PublicationIndexSchema.ELEMENT_SIZE, attachment.getSize());
attachmentsArray[i] = element;
}
pMap.put(PublicationIndexSchema.ATTACHMENT, attachmentsArray);
// Catalogs
Catalog[] catalogs = publication.getCatalogs();
HashMap<String, Object>[] catalogsArray = new HashMap[catalogs.length];
for (int i = 0; i < catalogsArray.length; i++) {
Catalog catalog = catalogs[i];
HashMap<String, Object> element = new HashMap<String, Object>();
element.put(PublicationIndexSchema.ELEMENT_ID, catalog.getIdentifier());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_MIMETYPE, catalog.getMimeType());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_TYPE, catalog.getElementType());
element.put(PublicationIndexSchema.ELEMENT_TAG, catalog.getTags());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_URL, catalog.getURI());
element.put(PublicationIndexSchema.ELEMENT_SIZE, catalog.getSize());
catalogsArray[i] = element;
}
pMap.put(PublicationIndexSchema.CATALOG, catalogsArray);
// Tracks
Track[] tracks = publication.getTracks();
HashMap<String, Object>[] tracksArray = new HashMap[tracks.length];
for (int i = 0; i < tracksArray.length; i++) {
Track track = tracks[i];
HashMap<String, Object> element = new HashMap<String, Object>();
element.put(PublicationIndexSchema.ELEMENT_ID, track.getIdentifier());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_MIMETYPE, track.getMimeType());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_TYPE, track.getElementType());
element.put(PublicationIndexSchema.ELEMENT_TAG, track.getTags());
addObjectStringtToMap(element, PublicationIndexSchema.ELEMENT_URL, track.getURI());
element.put(PublicationIndexSchema.ELEMENT_SIZE, track.getSize());
element.put(PublicationIndexSchema.TRACK_DURATION, track.getDuration());
tracksArray[i] = element;
}
pMap.put(PublicationIndexSchema.TRACK, tracksArray);
return pMap;
}
/**
* Adds authorization fields to the input document.
*
* @param doc
* the input document
* @param aclString
* the access control list string
*/
private static void addAuthorization(SearchMetadataCollection doc, String aclString) {
Map<String, List<String>> permissions = new HashMap<String, List<String>>();
// Define containers for common permissions
for (Action action : Permissions.Action.values()) {
permissions.put(action.toString(), new ArrayList<String>());
}
AccessControlList acl = AccessControlParser.parseAclSilent(aclString);
for (AccessControlEntry entry : acl.getEntries()) {
if (!entry.isAllow()) {
logger.info("Event index does not support denial via ACL, ignoring {}", entry);
continue;
}
List<String> actionPermissions = permissions.get(entry.getAction());
if (actionPermissions == null) {
actionPermissions = new ArrayList<String>();
permissions.put(entry.getAction(), actionPermissions);
}
actionPermissions.add(entry.getRole());
}
// Write the permissions to the input document
for (Map.Entry<String, List<String>> entry : permissions.entrySet()) {
String fieldName = EventIndexSchema.ACL_PERMISSION_PREFIX.concat(entry.getKey());
doc.addField(fieldName, entry.getValue(), false);
}
}
/**
* Loads the recording event from the search index or creates a new one that can then be persisted.
*
* @param mediapackageId
* the mediapackage identifier
* @param organization
* the organization
* @param user
* the user
* @param searchIndex
* the {@link AbstractSearchIndex} to search in
* @return the recording event
* @throws SearchIndexException
* if querying the search index fails
* @throws IllegalStateException
* if multiple recording events with the same identifier are found
*/
public static Event getOrCreateEvent(String mediapackageId, String organization, User user,
AbstractSearchIndex searchIndex) throws SearchIndexException {
EventSearchQuery query = new EventSearchQuery(organization, user).withoutActions().withIdentifier(mediapackageId);
SearchResult<Event> searchResult = searchIndex.getByQuery(query);
if (searchResult.getDocumentCount() == 0) {
return new Event(mediapackageId, organization);
} else if (searchResult.getDocumentCount() == 1) {
return searchResult.getItems()[0].getSource();
} else {
throw new IllegalStateException(
"Multiple recording events with identifier " + mediapackageId + " found in search index");
}
}
/**
* Loads the recording event from the search index
*
* @param mediapackageId
* the mediapackage identifier
* @param organization
* the organization
* @param user
* the user
* @param searchIndex
* the {@link AbstractSearchIndex} to search in
* @return the recording event or <code>null</code> if not found
* @throws SearchIndexException
* if querying the search index fails
* @throws IllegalStateException
* if multiple recording events with the same identifier are found
*/
public static Event getEvent(String mediapackageId, String organization, User user, AbstractSearchIndex searchIndex)
throws SearchIndexException {
EventSearchQuery query = new EventSearchQuery(organization, user).withoutActions().withIdentifier(mediapackageId);
SearchResult<Event> searchResult = searchIndex.getByQuery(query);
if (searchResult.getDocumentCount() == 0) {
return null;
} else if (searchResult.getDocumentCount() == 1) {
return searchResult.getItems()[0].getSource();
} else {
throw new IllegalStateException(
"Multiple recording events with identifier " + mediapackageId + " found in search index");
}
}
/**
* Update the given {@link Event} with the given {@link DublinCore}.
*
* @param event
* the event to update
* @param dc
* the catalog with the metadata for the update
* @return the updated event
*/
public static Event updateEvent(Event event, DublinCore dc) {
event.setTitle(dc.getFirst(DublinCore.PROPERTY_TITLE));
event.setDescription(dc.getFirst(DublinCore.PROPERTY_DESCRIPTION));
event.setSubject(dc.getFirst(DublinCore.PROPERTY_SUBJECT));
event.setLocation(dc.getFirst(DublinCore.PROPERTY_SPATIAL));
event.setLanguage(dc.getFirst(DublinCore.PROPERTY_LANGUAGE));
event.setSource(dc.getFirst(DublinCore.PROPERTY_SOURCE));
event.setSeriesId(dc.getFirst(DublinCore.PROPERTY_IS_PART_OF));
event.setLicense(dc.getFirst(DublinCore.PROPERTY_LICENSE));
event.setRights(dc.getFirst(DublinCore.PROPERTY_RIGHTS_HOLDER));
Date created;
String encodedDate = dc.getFirst(DublinCore.PROPERTY_CREATED);
if (StringUtils.isBlank(encodedDate)) {
created = new Date();
} else {
created = EncodingSchemeUtils.decodeDate(encodedDate);
}
event.setCreated(DateTimeSupport.toUTC(created.getTime()));
String strPeriod = dc.getFirst(DublinCore.PROPERTY_TEMPORAL);
try {
if (StringUtils.isNotBlank(strPeriod)) {
DCMIPeriod period = EncodingSchemeUtils.decodeMandatoryPeriod(strPeriod);
event.setRecordingStartDate(DateTimeSupport.toUTC(period.getStart().getTime()));
event.setRecordingEndDate(DateTimeSupport.toUTC(period.getEnd().getTime()));
event.setDuration(period.getEnd().getTime() - period.getStart().getTime());
} else {
event.setRecordingStartDate(DateTimeSupport.toUTC(created.getTime()));
}
} catch (Exception e) {
logger.warn("Invalid start and end date/time for event {}: {}", event.getIdentifier(), strPeriod);
event.setRecordingStartDate(DateTimeSupport.toUTC(created.getTime()));
}
updateTechnicalDate(event);
// TODO: Add support for language
event.setContributors(splitStringList(dc.get(DublinCore.PROPERTY_CONTRIBUTOR, DublinCore.LANGUAGE_ANY)));
event.setPresenters(splitStringList(dc.get(DublinCore.PROPERTY_CREATOR, DublinCore.LANGUAGE_ANY)));
return event;
}
public static Event updateTechnicalDate(Event event) {
if (event.hasRecordingStarted()) {
// Override technical dates from recording if already started
event.setTechnicalStartTime(event.getRecordingStartDate());
event.setTechnicalEndTime(event.getRecordingEndDate());
} else {
// If this is an upload where the start time is not set, set the start time to same as dublin core
if (StringUtils.isBlank(event.getTechnicalStartTime()))
event.setTechnicalStartTime(event.getRecordingStartDate());
if (StringUtils.isBlank(event.getTechnicalEndTime()))
event.setTechnicalEndTime(event.getRecordingEndDate());
}
return event;
}
/**
* Update the given {@link Event} with the given {@link MediaPackage}.
*
* @param event
* the event to update
* @param mp
* the mediapackage containing the metadata for the update
* @return the updated event
*/
public static Event updateEvent(Event event, MediaPackage mp) {
// Tracks
List<String> trackMimeTypes = new ArrayList<String>();
List<String> trackStreamResolutions = new ArrayList<String>();
List<String> trackFlavors = new ArrayList<String>();
for (Track t : mp.getTracks()) {
if (t.getMimeType() != null)
trackMimeTypes.add(t.getMimeType().toString());
if (t.getFlavor() != null)
trackFlavors.add(t.getFlavor().toString());
VideoStream[] streams = TrackSupport.byType(t.getStreams(), VideoStream.class);
for (VideoStream s : streams) {
trackStreamResolutions.add(s.getFrameWidth() + "x" + s.getFrameHeight());
}
}
event.setTrackMimetypes(trackMimeTypes);
event.setTrackStreamResolutions(trackStreamResolutions);
event.setTrackFlavors(trackFlavors);
// Metadata
List<String> metadataFlavors = new ArrayList<String>();
List<String> metadataMimetypes = new ArrayList<String>();
for (Catalog c : mp.getCatalogs()) {
if (c.getFlavor() != null)
metadataFlavors.add(c.getFlavor().toString());
if (c.getMimeType() != null)
metadataMimetypes.add(c.getMimeType().toString());
}
event.setMetadataFlavors(metadataFlavors);
event.setMetadataMimetypes(metadataMimetypes);
// Attachments
List<String> attachmentFlavors = new ArrayList<String>();
for (Attachment a : mp.getAttachments()) {
if (a.getFlavor() != null)
attachmentFlavors.add(a.getFlavor().toString());
}
event.setAttachmentFlavors(attachmentFlavors);
// Publications
List<Publication> publications = new ArrayList<Publication>();
for (Publication p : mp.getPublications()) {
publications.add(p);
}
event.setPublications(publications);
event.setSeriesName(mp.getSeriesTitle());
return event;
}
/**
* A function to update the series title within an event. Uses the default number of attempts to get the series title
* and the default amount of time to sleep between attempts.
*
* @param event
* The event to update the series name in
* @param organization
* The organization for this event and series
* @param user
* The user
* @param searchIndex
* The index to search for the series
*/
public static void updateSeriesName(Event event, String organization, User user, AbstractSearchIndex searchIndex)
throws SearchIndexException {
updateSeriesName(event, organization, user, searchIndex, DEFAULT_ATTEMPTS, DEFAULT_SLEEP);
}
/**
* A function to update the series title within an event.
*
* @param event
* The event to update the series name in
* @param organization
* The organization for this event and series
* @param user
* The user
* @param searchIndex
* The index to search for the series
* @param tries
* The number of attempts to try to get the series title
* @param sleep
* The amount of time in ms to sleep between attempts to get the series title.
*/
public static void updateSeriesName(Event event, String organization, User user, AbstractSearchIndex searchIndex,
int tries, long sleep) throws SearchIndexException {
if (event.getSeriesId() != null) {
for (int i = 1; i <= tries; i++) {
SearchResult<Series> result = searchIndex.getByQuery(
new SeriesSearchQuery(organization, user).withoutActions().withIdentifier(event.getSeriesId()));
if (result.getHitCount() > 0) {
event.setSeriesName(result.getItems()[0].getSource().getTitle());
break;
} else {
Integer triesLeft = new Integer(tries - i);
logger.debug("Not able to find the series {} in the search index for the event {}. Will try {} more times.",
new Object[] { event.getSeriesId(), event.getIdentifier(), triesLeft });
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
logger.warn("Interupted while sleeping before checking for the series being added to the index {}",
ExceptionUtils.getStackTrace(e));
}
}
}
}
}
/**
* Update an event with the given has comments and has open comments status.
*
* @param eventId
* the event id
* @param hasComments
* whether it has comments
* @param hasOpenComments
* whether it has open comments
* @param organization
* the organization
* @param user
* the user
* @param searchIndex
* the serach index
* @throws SearchIndexException
* if error occurs
* @throws NotFoundException
* if event has not been found
*/
public static void updateComments(String eventId, boolean hasComments, boolean hasOpenComments, boolean needsCutting,
String organization, User user, AbstractSearchIndex searchIndex) throws SearchIndexException, NotFoundException {
if (!hasComments && hasOpenComments)
throw new IllegalStateException(
"Invalid comment update request: You can't have open comments without having any comments!");
if (!hasOpenComments && needsCutting)
throw new IllegalStateException(
"Invalid comment update request: You can't have an needs cutting comment without having any open comments!");
Event event = getEvent(eventId, organization, user, searchIndex);
if (event == null)
throw new NotFoundException("No event with id " + eventId + " found.");
event.setHasComments(hasComments);
event.setHasOpenComments(hasOpenComments);
event.setNeedsCutting(needsCutting);
try {
searchIndex.addOrUpdate(event);
} catch (SearchIndexException e) {
logger.warn("Unable to update event '{}': {}", event, ExceptionUtils.getStackTrace(e));
}
}
/**
* Update a managed acl name to a new one.
*
* @param currentManagedAcl
* The current unique managed acl name to look for in the events.
* @param newManagedAcl
* The new managed acl name to update all of the events to.
* @param organization
* The organization for the managed acl.
* @param user
* The user.
* @param searchIndex
* The index to update with the new managed acl name.
*/
public static void updateManagedAclName(String currentManagedAcl, String newManagedAcl, String organization,
User user, AbstractSearchIndex searchIndex) {
SearchResult<Event> result = null;
try {
result = searchIndex
.getByQuery(new EventSearchQuery(organization, user).withoutActions().withManagedAcl(currentManagedAcl));
} catch (SearchIndexException e) {
logger.error("Unable to find the events in org '{}' with current managed acl name '{}' for event because {}",
new Object[] { organization, currentManagedAcl, ExceptionUtils.getStackTrace(e) });
}
if (result != null && result.getHitCount() > 0) {
for (SearchResultItem<Event> eventItem : result.getItems()) {
Event event = eventItem.getSource();
event.setManagedAcl(newManagedAcl);
try {
searchIndex.addOrUpdate(event);
} catch (SearchIndexException e) {
logger.warn(
"Unable to update event '{}' from current managed acl '{}' to new managed acl name '{}' because {}",
new Object[] { event, currentManagedAcl, newManagedAcl, ExceptionUtils.getStackTrace(e) });
}
}
}
}
/**
* Remove a managed acl from all events that have it.
*
* @param managedAcl
* The managed acl unique name to remove.
* @param organization
* The organization for the managed acl
* @param user
* The user
* @param searchIndex
* The search index to remove the managed acl from.
*/
public static void deleteManagedAcl(String managedAcl, String organization, User user,
AbstractSearchIndex searchIndex) {
SearchResult<Event> result = null;
try {
result = searchIndex
.getByQuery(new EventSearchQuery(organization, user).withoutActions().withManagedAcl(managedAcl));
} catch (SearchIndexException e) {
logger.error("Unable to find the events in org '{}' with current managed acl name '{}' for event because {}",
new Object[] { organization, managedAcl, ExceptionUtils.getStackTrace(e) });
}
if (result != null && result.getHitCount() > 0) {
for (SearchResultItem<Event> eventItem : result.getItems()) {
Event event = eventItem.getSource();
event.setManagedAcl(null);
try {
searchIndex.addOrUpdate(event);
} catch (SearchIndexException e) {
logger.warn("Unable to update event '{}' to remove managed acl '{}' because {}",
new Object[] { event, managedAcl, ExceptionUtils.getStackTrace(e) });
}
}
}
}
/**
* Gets all of the MediaPackageElement's flavors.
*
* @param publications
* The list of publication elements to get the flavors from.
* @return An array of {@link String} representation of the MediaPackageElementFlavors
*/
private static String[] getPublicationFlavors(List<Publication> publications) {
Set<String> allPublicationFlavors = new TreeSet<String>();
for (Publication p : publications) {
for (Attachment attachment : p.getAttachments()) {
if (attachment.getFlavor() != null)
allPublicationFlavors.add(attachment.getFlavor().toString());
}
for (Catalog catalog : p.getCatalogs()) {
if (catalog.getFlavor() != null)
allPublicationFlavors.add(catalog.getFlavor().toString());
}
for (Track track : p.getTracks()) {
if (track.getFlavor() != null)
allPublicationFlavors.add(track.getFlavor().toString());
}
}
return allPublicationFlavors.toArray(new String[allPublicationFlavors.size()]);
}
/**
* Returns <code>true</code> if the previewSubtype matches any of the publicationFlavors.
*
* @param publications
* @param previewSubtype
* @return
*/
public static Boolean subflavorMatches(List<Publication> publications, String previewSubtype) {
String[] publicationFlavors = getPublicationFlavors(publications);
if (publicationFlavors != null && previewSubtype != null) {
final String subtype = "/" + previewSubtype;
for (String flavor : publicationFlavors) {
if (flavor.endsWith(subtype)) {
return true;
}
}
}
return false;
}
}