use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class ExecuteServiceImpl method doProcess.
/**
* Does the actual processing, given a mediapackage (Execute Once WOH)
*
* @param arguments
* The list containing the program and its arguments
* @param mp
* MediaPackage used in the operation
* @param outFileName
* The name of the resulting file
* @param expectedType
* The expected element type
* @return A {@code String} containing the command output
* @throws ExecuteException
* if some internal error occurred
*/
protected String doProcess(List<String> arguments, MediaPackage mp, String outFileName, Type expectedType) throws ExecuteException {
String params = arguments.remove(1);
File outFile = null;
MediaPackageElement[] elementsByFlavor = null;
try {
if (outFileName != null) {
// FIXME : Find a better way to place the output File
File firstElement = workspace.get(mp.getElements()[0].getURI());
outFile = new File(firstElement.getParentFile(), outFileName);
}
// Get the substitution pattern.
// The following pattern matches, any construct with the form
// #{name}
// , where 'name' is the value of a certain property. It is stored in the backreference group 1.
// Optionally, expressions can take a parameter, like
// #{name(parameter)}
// , where 'parameter' is the name of a certain parameter.
// If specified, 'parameter' is stored in the group 2. Otherwise it's null.
// Both name and parameter match any character sequence that does not contain {, }, ( or ) .
Pattern pat = Pattern.compile("#\\{([^\\{\\}\\(\\)]+)(?:\\(([^\\{\\}\\(\\)]+)\\))?\\}");
// Substitute the appearances of the patterns with the actual absolute paths
Matcher matcher = pat.matcher(params);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// group(1) = property. group(2) = (optional) parameter
if (matcher.group(1).equals("id")) {
matcher.appendReplacement(sb, mp.getIdentifier().toString());
} else if (matcher.group(1).equals("flavor")) {
elementsByFlavor = mp.getElementsByFlavor(MediaPackageElementFlavor.parseFlavor(matcher.group(2)));
if (elementsByFlavor.length == 0)
throw new ExecuteException("No elements in the MediaPackage match the flavor '" + matcher.group(2) + "'.");
if (elementsByFlavor.length > 1)
logger.warn("Found more than one element with flavor '{}'. Using {} by default...", matcher.group(2), elementsByFlavor[0].getIdentifier());
File elementFile = workspace.get(elementsByFlavor[0].getURI());
matcher.appendReplacement(sb, elementFile.getAbsolutePath());
} else if (matcher.group(1).equals("out")) {
matcher.appendReplacement(sb, outFile.getAbsolutePath());
} else if (properties.get(matcher.group(1)) != null) {
matcher.appendReplacement(sb, (String) properties.get(matcher.group(1)));
} else if (bundleContext.getProperty(matcher.group(1)) != null) {
matcher.appendReplacement(sb, bundleContext.getProperty(matcher.group(1)));
}
}
matcher.appendTail(sb);
params = sb.toString();
} catch (IllegalArgumentException e) {
throw new ExecuteException("Tag 'flavor' must specify a valid MediaPackage element flavor.", e);
} catch (NotFoundException e) {
throw new ExecuteException("The element '" + elementsByFlavor[0].getURI().toString() + "' does not exist in the workspace.", e);
} catch (IOException e) {
throw new ExecuteException("Error retrieving MediaPackage element from workspace: '" + elementsByFlavor[0].getURI().toString() + "'.", e);
}
arguments.addAll(splitParameters(params));
return runCommand(arguments, outFile, expectedType);
}
use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class ExecuteManyWorkflowOperationHandler method start.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
* JobContext)
*/
@Override
public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
MediaPackage mediaPackage = workflowInstance.getMediaPackage();
WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
logger.debug("Running execute workflow operation with ID {}", operation.getId());
// Get operation parameters
String exec = StringUtils.trimToNull(operation.getConfiguration(EXEC_PROPERTY));
String params = StringUtils.trimToNull(operation.getConfiguration(PARAMS_PROPERTY));
float load = 1.0f;
String loadPropertyStr = StringUtils.trimToEmpty(operation.getConfiguration(LOAD_PROPERTY));
if (StringUtils.isNotBlank(loadPropertyStr)) {
try {
load = Float.parseFloat(loadPropertyStr);
} catch (NumberFormatException e) {
String description = StringUtils.trimToEmpty(operation.getDescription());
logger.warn("Ignoring invalid load value '{}' on execute operation with description '{}'", loadPropertyStr, description);
}
}
String sourceFlavor = StringUtils.trimToNull(operation.getConfiguration(SOURCE_FLAVOR_PROPERTY));
String sourceTags = StringUtils.trimToNull(operation.getConfiguration(SOURCE_TAGS_PROPERTY));
String targetFlavorStr = StringUtils.trimToNull(operation.getConfiguration(TARGET_FLAVOR_PROPERTY));
String targetTags = StringUtils.trimToNull(operation.getConfiguration(TARGET_TAGS_PROPERTY));
String outputFilename = StringUtils.trimToNull(operation.getConfiguration(OUTPUT_FILENAME_PROPERTY));
String expectedTypeStr = StringUtils.trimToNull(operation.getConfiguration(EXPECTED_TYPE_PROPERTY));
MediaPackageElementFlavor matchingFlavor = null;
if (sourceFlavor != null)
matchingFlavor = MediaPackageElementFlavor.parseFlavor(sourceFlavor);
// Unmarshall target flavor
MediaPackageElementFlavor targetFlavor = null;
if (targetFlavorStr != null)
targetFlavor = MediaPackageElementFlavor.parseFlavor(targetFlavorStr);
// Unmarshall expected mediapackage element type
MediaPackageElement.Type expectedType = null;
if (expectedTypeStr != null) {
for (MediaPackageElement.Type type : MediaPackageElement.Type.values()) if (type.toString().equalsIgnoreCase(expectedTypeStr)) {
expectedType = type;
break;
}
if (expectedType == null)
throw new WorkflowOperationException("'" + expectedTypeStr + "' is not a valid element type");
}
List<String> sourceTagList = asList(sourceTags);
// Select the tracks based on source flavors and tags
Set<MediaPackageElement> inputSet = new HashSet<>();
for (MediaPackageElement element : mediaPackage.getElementsByTags(sourceTagList)) {
MediaPackageElementFlavor elementFlavor = element.getFlavor();
if (sourceFlavor == null || (elementFlavor != null && elementFlavor.matches(matchingFlavor))) {
inputSet.add(element);
}
}
if (inputSet.size() == 0) {
logger.warn("Mediapackage {} has no suitable elements to execute the command {} based on tags {} and flavor {}", mediaPackage, exec, sourceTags, sourceFlavor);
return createResult(mediaPackage, Action.CONTINUE);
}
MediaPackageElement[] inputElements = inputSet.toArray(new MediaPackageElement[inputSet.size()]);
try {
Job[] jobs = new Job[inputElements.length];
MediaPackageElement[] resultElements = new MediaPackageElement[inputElements.length];
long totalTimeInQueue = 0;
for (int i = 0; i < inputElements.length; i++) jobs[i] = executeService.execute(exec, params, inputElements[i], outputFilename, expectedType, load);
// Wait for all jobs to be finished
if (!waitForStatus(jobs).isSuccess())
throw new WorkflowOperationException("Execute operation failed");
// Find which output elements are tracks and inspect them
HashMap<Integer, Job> jobMap = new HashMap<>();
for (int i = 0; i < jobs.length; i++) {
// Add this job's queue time to the total
totalTimeInQueue += jobs[i].getQueueTime();
if (StringUtils.trimToNull(jobs[i].getPayload()) != null) {
resultElements[i] = MediaPackageElementParser.getFromXml(jobs[i].getPayload());
if (resultElements[i].getElementType() == MediaPackageElement.Type.Track) {
jobMap.put(i, inspectionService.inspect(resultElements[i].getURI()));
}
} else
resultElements[i] = inputElements[i];
}
if (jobMap.size() > 0) {
if (!waitForStatus(jobMap.values().toArray(new Job[jobMap.size()])).isSuccess())
throw new WorkflowOperationException("Execute operation failed in track inspection");
for (Entry<Integer, Job> entry : jobMap.entrySet()) {
// Add this job's queue time to the total
totalTimeInQueue += entry.getValue().getQueueTime();
resultElements[entry.getKey()] = MediaPackageElementParser.getFromXml(entry.getValue().getPayload());
}
}
for (int i = 0; i < resultElements.length; i++) {
if (resultElements[i] != inputElements[i]) {
// Store new element to mediaPackage
mediaPackage.addDerived(resultElements[i], inputElements[i]);
// Store new element to mediaPackage
URI uri = workspace.moveTo(resultElements[i].getURI(), mediaPackage.getIdentifier().toString(), resultElements[i].getIdentifier(), outputFilename);
resultElements[i].setURI(uri);
// Set new flavor
if (targetFlavor != null)
resultElements[i].setFlavor(targetFlavor);
}
// Set new tags
if (targetTags != null) {
// Assume the tags starting with "-" means we want to eliminate such tags form the result element
for (String tag : asList(targetTags)) {
if (tag.startsWith("-"))
// We remove the tag resulting from stripping all the '-' characters at the beginning of the tag
resultElements[i].removeTag(tag.replaceAll("^-+", ""));
else
resultElements[i].addTag(tag);
}
}
}
WorkflowOperationResult result = createResult(mediaPackage, Action.CONTINUE, totalTimeInQueue);
logger.debug("Execute operation {} completed", operation.getId());
return result;
} catch (ExecuteException e) {
throw new WorkflowOperationException(e);
} catch (MediaPackageException e) {
throw new WorkflowOperationException("Some result element couldn't be serialized", e);
} catch (NotFoundException e) {
throw new WorkflowOperationException("Could not find mediapackage", e);
} catch (IOException e) {
throw new WorkflowOperationException("Error unmarshalling a result mediapackage element", e);
} catch (MediaInspectionException e) {
throw new WorkflowOperationException("Error inspecting one of the created tracks", e);
}
}
use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class SchedulerServiceImpl method loadEpisodeDublinCoreFromAsset.
private Opt<DublinCoreCatalog> loadEpisodeDublinCoreFromAsset(Snapshot snapshot) {
Option<MediaPackageElement> dcCatalog = mlist(snapshot.getMediaPackage().getElements()).filter(MediaPackageSupport.Filters.isEpisodeDublinCore).headOpt();
if (dcCatalog.isNone())
return Opt.none();
Opt<Asset> asset = assetManager.getAsset(snapshot.getVersion(), snapshot.getMediaPackage().getIdentifier().compact(), dcCatalog.get().getIdentifier());
if (asset.isNone())
return Opt.none();
if (Availability.OFFLINE.equals(asset.get().getAvailability()))
return Opt.none();
InputStream inputStream = null;
try {
inputStream = asset.get().getInputStream();
return Opt.some(DublinCores.read(inputStream));
} finally {
IOUtils.closeQuietly(inputStream);
}
}
use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class SchedulerServiceImpl method loadEpisodeAclFromAsset.
private Opt<AccessControlList> loadEpisodeAclFromAsset(Snapshot snapshot) {
Option<MediaPackageElement> acl = mlist(snapshot.getMediaPackage().getElements()).filter(MediaPackageSupport.Filters.isEpisodeAcl).headOpt();
if (acl.isNone())
return Opt.none();
Opt<Asset> asset = assetManager.getAsset(snapshot.getVersion(), snapshot.getMediaPackage().getIdentifier().compact(), acl.get().getIdentifier());
if (asset.isNone())
return Opt.none();
if (Availability.OFFLINE.equals(asset.get().getAvailability()))
return Opt.none();
InputStream inputStream = null;
try {
inputStream = asset.get().getInputStream();
return Opt.some(XACMLUtils.parseXacml(inputStream));
} catch (Exception e) {
logger.warn("Unable to parse access control list: {}", getStackTrace(e));
return Opt.none();
} finally {
IOUtils.closeQuietly(inputStream);
}
}
use of org.opencastproject.mediapackage.MediaPackageElement 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