use of org.opencastproject.workflow.api.WorkflowOperationException 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.workflow.api.WorkflowOperationException in project opencast by opencast.
the class CloneWorkflowOperationHandler method copyElement.
private MediaPackageElement copyElement(MediaPackageElement element) throws WorkflowOperationException {
String elementId = UUID.randomUUID().toString();
MediaPackageElement newElement = (MediaPackageElement) element.clone();
newElement.setIdentifier(elementId);
File sourceFile = null;
String toFileName = null;
try {
URI sourceURI = element.getURI();
sourceFile = workspace.get(sourceURI);
toFileName = elementId;
String extension = FilenameUtils.getExtension(sourceFile.getName());
if (!"".equals(extension))
toFileName += "." + extension;
logger.debug("Start copying element {} to target {}.", sourceFile.getPath(), toFileName);
URI newUri = workspace.put(element.getMediaPackage().getIdentifier().toString(), newElement.getIdentifier(), toFileName, workspace.read(sourceURI));
newElement.setURI(newUri);
newElement.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, workspace.get(newUri)));
logger.debug("Element {} copied to target {}.", sourceFile.getPath(), toFileName);
} catch (IOException e) {
throw new WorkflowOperationException("Unable to copy " + sourceFile.getPath() + " to " + toFileName + ".", e);
} catch (NotFoundException e) {
throw new WorkflowOperationException("Unable to find " + element.getURI() + " in the workspace", e);
}
return newElement;
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class DuplicateEventWorkflowOperationHandler method start.
@Override
public WorkflowOperationResult start(final WorkflowInstance workflowInstance, final JobContext context) throws WorkflowOperationException {
final MediaPackage mediaPackage = workflowInstance.getMediaPackage();
final WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
final String configuredSourceFlavors = trimToEmpty(operation.getConfiguration(SOURCE_FLAVORS_PROPERTY));
final String configuredSourceTags = trimToEmpty(operation.getConfiguration(SOURCE_TAGS_PROPERTY));
final String configuredTargetTags = trimToEmpty(operation.getConfiguration(TARGET_TAGS_PROPERTY));
final int numberOfEvents = Integer.parseInt(operation.getConfiguration(NUMBER_PROPERTY));
final String configuredPropertyNamespaces = trimToEmpty(operation.getConfiguration(PROPERTY_NAMESPACES_PROPERTY));
int maxNumberOfEvents = MAX_NUMBER_DEFAULT;
if (operation.getConfiguration(MAX_NUMBER_PROPERTY) != null) {
maxNumberOfEvents = Integer.parseInt(operation.getConfiguration(MAX_NUMBER_PROPERTY));
}
if (numberOfEvents > maxNumberOfEvents) {
throw new WorkflowOperationException("Number of events to create exceeds the maximum of " + maxNumberOfEvents + ". Aborting.");
}
logger.info("Creating {} new media packages from media package with id {}.", numberOfEvents, mediaPackage.getIdentifier());
final String[] sourceTags = split(configuredSourceTags, ",");
final String[] targetTags = split(configuredTargetTags, ",");
final String[] sourceFlavors = split(configuredSourceFlavors, ",");
final String[] propertyNamespaces = split(configuredPropertyNamespaces, ",");
final String copyNumberPrefix = trimToEmpty(operation.getConfiguration(COPY_NUMBER_PREFIX_PROPERTY));
final SimpleElementSelector elementSelector = new SimpleElementSelector();
for (String flavor : sourceFlavors) {
elementSelector.addFlavor(MediaPackageElementFlavor.parseFlavor(flavor));
}
final List<String> removeTags = new ArrayList<>();
final List<String> addTags = new ArrayList<>();
final List<String> overrideTags = new ArrayList<>();
for (String tag : targetTags) {
if (tag.startsWith(MINUS)) {
removeTags.add(tag);
} else if (tag.startsWith(PLUS)) {
addTags.add(tag);
} else {
overrideTags.add(tag);
}
}
for (String tag : sourceTags) {
elementSelector.addTag(tag);
}
// Filter elements to copy based on input tags and input flavors
final Collection<MediaPackageElement> elements = elementSelector.select(mediaPackage, false);
final Collection<Publication> internalPublications = new HashSet<>();
for (MediaPackageElement e : mediaPackage.getElements()) {
if (e instanceof Publication && InternalPublicationChannel.CHANNEL_ID.equals(((Publication) e).getChannel())) {
internalPublications.add((Publication) e);
}
if (MediaPackageElements.EPISODE.equals(e.getFlavor())) {
// Remove episode DC since we will add a new one (with changed title)
elements.remove(e);
}
}
final MediaPackageElement[] originalEpisodeDc = mediaPackage.getElementsByFlavor(MediaPackageElements.EPISODE);
if (originalEpisodeDc.length != 1) {
throw new WorkflowOperationException("Media package " + mediaPackage.getIdentifier() + " has " + originalEpisodeDc.length + " episode dublin cores while it is expected to have exactly 1. Aborting.");
}
for (int i = 0; i < numberOfEvents; i++) {
final List<URI> temporaryFiles = new ArrayList<>();
MediaPackage newMp = null;
try {
// Clone the media package (without its elements)
newMp = copyMediaPackage(mediaPackage, i + 1, copyNumberPrefix);
// Create and add new episode dublin core with changed title
newMp = copyDublinCore(mediaPackage, originalEpisodeDc[0], newMp, removeTags, addTags, overrideTags, temporaryFiles);
// Clone regular elements
for (final MediaPackageElement e : elements) {
final MediaPackageElement element = (MediaPackageElement) e.clone();
updateTags(element, removeTags, addTags, overrideTags);
newMp.add(element);
}
// Clone internal publications
for (final Publication originalPub : internalPublications) {
copyPublication(originalPub, mediaPackage, newMp, removeTags, addTags, overrideTags, temporaryFiles);
}
assetManager.takeSnapshot(AssetManager.DEFAULT_OWNER, newMp);
// Clone properties of media package
for (String namespace : propertyNamespaces) {
copyProperties(namespace, mediaPackage, newMp);
}
} finally {
cleanup(temporaryFiles, Optional.ofNullable(newMp));
}
}
return createResult(mediaPackage, Action.CONTINUE);
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class DuplicateEventWorkflowOperationHandler method copyDublinCore.
private MediaPackage copyDublinCore(MediaPackage source, MediaPackageElement sourceDublinCore, MediaPackage destination, List<String> removeTags, List<String> addTags, List<String> overrideTags, List<URI> temporaryFiles) throws WorkflowOperationException {
final DublinCoreCatalog destinationDublinCore = DublinCoreUtil.loadEpisodeDublinCore(workspace, source).get();
destinationDublinCore.setIdentifier(null);
destinationDublinCore.setURI(sourceDublinCore.getURI());
destinationDublinCore.set(DublinCore.PROPERTY_TITLE, destination.getTitle());
try (InputStream inputStream = IOUtils.toInputStream(destinationDublinCore.toXmlString(), "UTF-8")) {
final String elementId = UUID.randomUUID().toString();
final URI newUrl = workspace.put(destination.getIdentifier().compact(), elementId, "dublincore.xml", inputStream);
temporaryFiles.add(newUrl);
final MediaPackageElement mpe = destination.add(newUrl, MediaPackageElement.Type.Catalog, MediaPackageElements.EPISODE);
mpe.setIdentifier(elementId);
for (String tag : sourceDublinCore.getTags()) {
mpe.addTag(tag);
}
updateTags(mpe, removeTags, addTags, overrideTags);
} catch (IOException e) {
throw new WorkflowOperationException(e);
}
return destination;
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class ExportWorkflowPropertiesWOH method start.
@Override
public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
logger.info("Start exporting workflow properties for workflow {}", workflowInstance);
final MediaPackage mediaPackage = workflowInstance.getMediaPackage();
final Set<String> keys = $(getOptConfig(workflowInstance, KEYS_PROPERTY)).bind(Strings.splitCsv).toSet();
final String targetFlavorString = getOptConfig(workflowInstance, TARGET_FLAVOR_PROPERTY).getOr(DEFAULT_TARGET_FLAVOR);
final Stream<String> targetTags = $(getOptConfig(workflowInstance, TARGET_TAGS_PROPERTY)).bind(Strings.splitCsv);
final MediaPackageElementFlavor targetFlavor = MediaPackageElementFlavor.parseFlavor(targetFlavorString);
// Read optional existing workflow properties from mediapackage
Properties workflowProps = new Properties();
Opt<Attachment> existingPropsElem = loadPropertiesElementFromMediaPackage(targetFlavor, workflowInstance);
if (existingPropsElem.isSome()) {
workflowProps = loadPropertiesFromXml(workspace, existingPropsElem.get().getURI());
// Remove specified keys
for (String key : keys) workflowProps.remove(key);
}
// Extend with specified properties
for (String key : workflowInstance.getConfigurationKeys()) {
if (keys.isEmpty() || keys.contains(key))
workflowProps.put(key, workflowInstance.getConfiguration(key));
}
// Store properties as an attachment
Attachment attachment;
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
workflowProps.storeToXML(out, null, "UTF-8");
String elementId = UUID.randomUUID().toString();
URI uri = workspace.put(mediaPackage.getIdentifier().compact(), elementId, EXPORTED_PROPERTIES_FILENAME, new ByteArrayInputStream(out.toByteArray()));
MediaPackageElementBuilder builder = MediaPackageElementBuilderFactory.newInstance().newElementBuilder();
attachment = (Attachment) builder.elementFromURI(uri, Attachment.TYPE, targetFlavor);
attachment.setMimeType(MimeTypes.XML);
} catch (IOException e) {
logger.error("Unable to store workflow properties as Attachment with flavor '{}': {}", targetFlavorString, ExceptionUtils.getStackTrace(e));
throw new WorkflowOperationException("Unable to store workflow properties as Attachment", e);
}
// Add the target tags
for (String tag : targetTags) {
logger.trace("Tagging with '{}'", tag);
attachment.addTag(tag);
}
// Update attachment
if (existingPropsElem.isSome())
mediaPackage.remove(existingPropsElem.get());
mediaPackage.add(attachment);
logger.info("Added properties from {} as Attachment with flavor {}", workflowInstance, targetFlavorString);
logger.debug("Workflow properties: {}", propertiesAsString(workflowProps));
return createResult(mediaPackage, null, Action.CONTINUE, 0);
}
Aggregations