use of org.opencastproject.assetmanager.api.query.AQueryBuilder in project opencast by opencast.
the class SchedulerServiceImpl method getCalendar.
@Override
public String getCalendar(Opt<String> captureAgentId, Opt<String> seriesId, Opt<Date> cutoff) throws SchedulerException {
try {
AQueryBuilder query = assetManager.createQuery();
Props p = new Props(query);
Predicate predicate = withOrganization(query).and(withOwner(query)).and(query.hasPropertiesOf(p.namespace())).and(p.optOut().eq(false)).and(withVersion(query)).and(p.end().ge(DateTime.now().minusHours(1).toDate()));
for (String agentId : captureAgentId) {
predicate = predicate.and(p.agent().eq(agentId));
}
for (String series : seriesId) {
predicate = predicate.and(query.seriesId().eq(series));
}
for (Date d : cutoff) {
predicate = predicate.and(p.start().le(d));
}
ASelectQuery select = query.select(query.snapshot(), p.agent().target(), p.start().target(), p.end().target(), query.propertiesOf(CA_NAMESPACE)).where(predicate);
Stream<ARecord> records = select.run().getRecords();
CalendarGenerator cal = new CalendarGenerator(seriesService);
for (ARecord record : records) {
boolean blacklisted;
// isBlacklisted() methods are not implemented in the persistence layer and return always false
// try {
// //blacklisted = isBlacklisted(record.getMediaPackageId());
// } catch (NotFoundException e) {
// continue;
// }
blacklisted = false;
// Skip blacklisted events
if (blacklisted)
continue;
Opt<MediaPackage> optMp = record.getSnapshot().map(episodeToMp);
// If the event media package is empty, skip the event
if (optMp.isNone()) {
logger.warn("Mediapackage for event '{}' can't be found, event is not recorded", record.getMediaPackageId());
continue;
}
Opt<DublinCoreCatalog> catalogOpt = loadEpisodeDublinCoreFromAsset(record.getSnapshot().get());
if (catalogOpt.isNone()) {
logger.warn("No episode catalog available, skipping!");
continue;
}
Map<String, String> caMetadata = record.getProperties().filter(filterByNamespace._2(CA_NAMESPACE)).group(toKey, toValue);
// If the even properties are empty, skip the event
if (caMetadata.isEmpty()) {
logger.warn("Properties for event '{}' can't be found, event is not recorded", record.getMediaPackageId());
continue;
}
String agentId = record.getProperties().apply(Properties.getString(AGENT_CONFIG));
Date start = record.getProperties().apply(Properties.getDate(START_DATE_CONFIG));
Date end = record.getProperties().apply(Properties.getDate(END_DATE_CONFIG));
Date lastModified = record.getSnapshot().get().getArchivalDate();
// Add the entry to the calendar, skip it with a warning if adding fails
try {
cal.addEvent(optMp.get(), catalogOpt.get(), agentId, start, end, lastModified, toPropertyString(caMetadata));
} catch (Exception e) {
logger.warn("Error adding event '{}' to calendar, event is not recorded: {}", record.getMediaPackageId(), getStackTrace(e));
continue;
}
}
// Only validate calendars with events. Without any events, the iCalendar won't validate
if (cal.getCalendar().getComponents().size() > 0) {
try {
cal.getCalendar().validate();
} catch (ValidationException e) {
logger.warn("Recording calendar could not be validated (returning it anyways): {}", getStackTrace(e));
}
}
return cal.getCalendar().toString();
} catch (Exception e) {
if (e instanceof SchedulerException)
throw e;
logger.error("Failed getting calendar: {}", getStackTrace(e));
throw new SchedulerException(e);
}
}
use of org.opencastproject.assetmanager.api.query.AQueryBuilder in project opencast by opencast.
the class SchedulerServiceImpl method updateRecordingState.
@Override
public boolean updateRecordingState(String id, String state) throws NotFoundException, SchedulerException {
notEmpty(id, "id");
notEmpty(state, "state");
if (!RecordingState.KNOWN_STATES.contains(state)) {
logger.warn("Invalid recording state: {}.", state);
return false;
}
try {
AQueryBuilder query = assetManager.createQuery();
Props p = new Props(query);
AResult result = query.select(p.recordingStatus().target(), p.recordingLastHeard().target()).where(withOrganization(query).and(query.mediaPackageId(id).and(query.version().isLatest()).and(query.hasPropertiesOf(p.namespace())))).run();
Opt<ARecord> record = result.getRecords().head();
if (record.isNone())
throw new NotFoundException();
Opt<String> recordingState = record.get().getProperties().apply(Properties.getStringOpt(RECORDING_STATE_CONFIG));
Opt<Long> lastHeard = record.get().getProperties().apply(Properties.getLongOpt(RECORDING_LAST_HEARD_CONFIG));
if (recordingState.isSome() && lastHeard.isSome()) {
Recording r = new RecordingImpl(id, recordingState.get(), lastHeard.get());
if (state.equals(r.getState())) {
logger.debug("Recording state not changed");
// Reset the state anyway so that the last-heard-from time is correct...
r.setState(state);
} else {
logger.debug("Setting Recording {} to state {}.", id, state);
r.setState(state);
sendRecordingUpdate(r);
}
assetManager.setProperty(p.recordingStatus().mk(id, r.getState()));
assetManager.setProperty(p.recordingLastHeard().mk(id, r.getLastCheckinTime()));
return true;
} else {
Recording r = new RecordingImpl(id, state);
assetManager.setProperty(p.recordingStatus().mk(id, r.getState()));
assetManager.setProperty(p.recordingLastHeard().mk(id, r.getLastCheckinTime()));
sendRecordingUpdate(r);
return true;
}
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
logger.error("Failed to update recording status of event with mediapackage '{}': {}", id, getStackTrace(e));
throw new SchedulerException(e);
}
}
use of org.opencastproject.assetmanager.api.query.AQueryBuilder in project opencast by opencast.
the class SchedulerServiceImpl method getScheduledEvents.
/*
* FIXME: This query is unsafe since it may fetch many many rows. It would be better to do conflict checking directly
* in the database instead of fetching all scheduled events for the capture agent and then doing the checks in memory.
* Unfortunately, the current database schema is not suitable to do this in an efficient manner. Especially the generic
* concept of 'properties' would lead to many nested queries.
*/
private ARecord[] getScheduledEvents(Opt<String> captureAgentId) {
AQueryBuilder query = assetManager.createQuery();
Props p = new Props(query);
Predicate predicate = withOrganization(query).and(withOwner(query)).and(query.hasPropertiesOf(p.namespace())).and(withVersion(query));
for (String agentId : captureAgentId) {
predicate = predicate.and(p.agent().eq(agentId));
}
return query.select(query.snapshot(), p.start().target(), p.end().target()).where(predicate).run().getRecords().toList().toArray(new ARecord[0]);
}
use of org.opencastproject.assetmanager.api.query.AQueryBuilder in project opencast by opencast.
the class SchedulerServiceImpl method getDublinCore.
@Override
public DublinCoreCatalog getDublinCore(String mediaPackageId) throws NotFoundException, SchedulerException {
notEmpty(mediaPackageId, "mediaPackageId");
try {
AQueryBuilder query = assetManager.createQuery();
Props p = new Props(query);
AResult result = query.select(query.snapshot()).where(withOrganization(query).and(query.mediaPackageId(mediaPackageId)).and(withVersion(query)).and(query.hasPropertiesOf(p.namespace()))).run();
Opt<ARecord> record = result.getRecords().head();
if (record.isNone())
throw new NotFoundException();
Opt<DublinCoreCatalog> dublinCore = loadEpisodeDublinCoreFromAsset(record.get().getSnapshot().get());
if (dublinCore.isNone())
throw new NotFoundException("No dublincore catalog found " + mediaPackageId);
return dublinCore.get();
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
logger.error("Failed to get dublin core catalog of event '{}': {}", mediaPackageId, getStackTrace(e));
throw new SchedulerException(e);
}
}
use of org.opencastproject.assetmanager.api.query.AQueryBuilder in project opencast by opencast.
the class SchedulerServiceImpl method addMultipleEventInternal.
private Map<String, Period> addMultipleEventInternal(List<Period> periods, String captureAgentId, Set<String> userIds, MediaPackage templateMp, Map<String, String> wfProperties, Map<String, String> caMetadata, String modificationOrigin, Opt<Boolean> optOutStatus, Opt<String> schedulingSource, Opt<String> trxId) throws SchedulerException {
notNull(periods, "periods");
requireTrue(periods.size() > 0, "periods");
notEmpty(captureAgentId, "captureAgentId");
notNull(userIds, "userIds");
notNull(templateMp, "mediaPackages");
notNull(wfProperties, "wfProperties");
notNull(caMetadata, "caMetadata");
notEmpty(modificationOrigin, "modificationOrigin");
notNull(optOutStatus, "optOutStatus");
notNull(schedulingSource, "schedulingSource");
notNull(trxId, "trxId");
Map<String, Period> scheduledEvents = new LinkedHashMap<>();
try {
LinkedList<Id> ids = new LinkedList<>();
AQueryBuilder qb = assetManager.createQuery();
Predicate p = null;
// While we don't have a list of IDs equal to the number of periods
while (ids.size() <= periods.size()) {
// Create a list of IDs equal to the number of periods, along with a set of AM predicates
while (ids.size() <= periods.size()) {
Id id = new IdImpl(UUID.randomUUID().toString());
ids.add(id);
Predicate np = qb.mediaPackageId(id.compact());
// Haha, p = np jokes with the AM query language. Ha. Haha. Ha. (Sob...)
if (null == p) {
p = np;
} else {
p = p.or(np);
}
}
// Select the list of ids which alread exist. Hint: this needs to be zero
AResult result = qb.select(qb.nothing()).where(withOrganization(qb).and(p).and(qb.version().isLatest())).run();
// If there is conflict, clear the list and start over
if (result.getTotalSize() > 0) {
ids.clear();
}
}
Opt<String> seriesId = Opt.nul(StringUtils.trimToNull(templateMp.getSeries()));
// Get opt out status
boolean optOut = getOptOutStatus(seriesId, optOutStatus);
if (trxId.isNone()) {
// Check for locked transactions
if (schedulingSource.isSome() && persistence.hasTransaction(schedulingSource.get())) {
logger.warn("Unable to add events, source '{}' is currently locked due to an active transaction!", schedulingSource.get());
throw new SchedulerTransactionLockException("Unable to add event, locked source " + schedulingSource.get());
}
// Check for conflicting events if not opted out
if (!optOut) {
List<MediaPackage> conflictingEvents = findConflictingEvents(periods, captureAgentId, TimeZone.getDefault());
if (conflictingEvents.size() > 0) {
logger.info("Unable to add events, conflicting events found: {}", conflictingEvents);
throw new SchedulerConflictException("Unable to add event, conflicting events found");
}
}
}
// counter for index into the list of mediapackages
int counter = 0;
for (Period event : periods) {
MediaPackage mediaPackage = (MediaPackage) templateMp.clone();
Date startDate = new Date(event.getStart().getTime());
Date endDate = new Date(event.getEnd().getTime());
Id id = ids.get(counter);
// Get, or make, the DC catalog
DublinCoreCatalog dc;
Opt<DublinCoreCatalog> dcOpt = DublinCoreUtil.loadEpisodeDublinCore(workspace, templateMp);
if (dcOpt.isSome()) {
dc = dcOpt.get();
dc = (DublinCoreCatalog) dc.clone();
// make sure to bind the OC_PROPERTY namespace
dc.addBindings(XmlNamespaceContext.mk(XmlNamespaceBinding.mk(DublinCores.OC_PROPERTY_NS_PREFIX, DublinCores.OC_PROPERTY_NS_URI)));
} else {
dc = DublinCores.mkOpencastEpisode().getCatalog();
}
// Set the new media package identifier
mediaPackage.setIdentifier(id);
// Update dublincore title and temporal
String newTitle = dc.getFirst(DublinCore.PROPERTY_TITLE) + String.format(" %0" + Integer.toString(periods.size()).length() + "d", ++counter);
dc.set(DublinCore.PROPERTY_TITLE, newTitle);
DublinCoreValue eventTime = EncodingSchemeUtils.encodePeriod(new DCMIPeriod(startDate, endDate), Precision.Second);
dc.set(DublinCore.PROPERTY_TEMPORAL, eventTime);
mediaPackage = updateDublincCoreCatalog(mediaPackage, dc);
mediaPackage.setTitle(newTitle);
String mediaPackageId = mediaPackage.getIdentifier().compact();
// Converting from iCal4j DateTime objects to plain Date objects to prevent AMQ issues below
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.setTime(event.getStart());
Date startDateTime = cal.getTime();
cal.setTime(event.getEnd());
Date endDateTime = cal.getTime();
// Load dublincore and acl for update
Opt<DublinCoreCatalog> dublinCore = DublinCoreUtil.loadEpisodeDublinCore(workspace, mediaPackage);
Option<AccessControlList> acl = authorizationService.getAcl(mediaPackage, AclScope.Episode);
// Get updated agent properties
Map<String, String> finalCaProperties = getFinalAgentProperties(caMetadata, wfProperties, captureAgentId, seriesId, dublinCore);
// Persist asset
String checksum = calculateChecksum(workspace, getEventCatalogUIAdapterFlavors(), startDateTime, endDateTime, captureAgentId, userIds, mediaPackage, dublinCore, wfProperties, finalCaProperties, optOut, acl.toOpt().getOr(new AccessControlList()));
persistEvent(mediaPackageId, modificationOrigin, checksum, Opt.some(startDateTime), Opt.some(endDateTime), Opt.some(captureAgentId), Opt.some(userIds), Opt.some(mediaPackage), Opt.some(wfProperties), Opt.some(finalCaProperties), Opt.some(optOut), schedulingSource, trxId);
if (trxId.isNone()) {
// Send updates
sendUpdateAddEvent(mediaPackageId, acl.toOpt(), dublinCore, Opt.some(startDateTime), Opt.some(endDateTime), Opt.some(userIds), Opt.some(captureAgentId), Opt.some(finalCaProperties), Opt.some(optOut));
// Update last modified
touchLastEntry(captureAgentId);
}
scheduledEvents.put(mediaPackageId, event);
for (MediaPackageElement mediaPackageElement : mediaPackage.getElements()) {
try {
workspace.delete(mediaPackage.getIdentifier().toString(), mediaPackageElement.getIdentifier());
} catch (NotFoundException | IOException e) {
logger.warn("Failed to delete media package element", e);
}
}
}
return scheduledEvents;
} catch (SchedulerException e) {
throw e;
} catch (Exception e) {
logger.error("Failed to create events: {}", getStackTrace(e));
throw new SchedulerException(e);
}
}
Aggregations