use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class WorkflowOperationWorker method start.
/**
* Starts executing the workflow operation.
*
* @return the workflow operation result
* @throws WorkflowOperationException
* if executing the workflow operation handler fails
* @throws WorkflowException
* if there is a problem processing the workflow
*/
public WorkflowOperationResult start() throws WorkflowOperationException, WorkflowException, UnauthorizedException {
final WorkflowOperationInstance operation = workflow.getCurrentOperation();
// Do we need to execute the operation?
// if
final String executionCondition = operation.getExecutionCondition();
final boolean execute;
if (executionCondition == null) {
execute = true;
} else {
final Result<Boolean> parsed = booleanExpressionEvaluator.eval(executionCondition);
if (parsed.isDefined() && parsed.getRest().isEmpty()) {
execute = parsed.getResult();
} else {
operation.setState(OperationState.FAILED);
throw new WorkflowOperationException(format("Unable to parse execution condition '%s'. Result is '%s'", executionCondition, parsed.toString()));
}
}
operation.setState(OperationState.RUNNING);
service.update(workflow);
try {
WorkflowOperationResult result = null;
if (execute) {
if (handler == null) {
// If there is no handler for the operation, yet we are supposed to run it, we must fail
logger.warn("No handler available to execute operation '{}'", operation.getTemplate());
throw new IllegalStateException("Unable to find a workflow handler for '" + operation.getTemplate() + "'");
}
result = handler.start(workflow, null);
} else {
// Allow for null handlers when we are skipping an operation
if (handler != null) {
result = handler.skip(workflow, null);
result.setAction(Action.SKIP);
}
}
return result;
} catch (Exception e) {
operation.setState(OperationState.FAILED);
if (e instanceof WorkflowOperationException)
throw (WorkflowOperationException) e;
throw new WorkflowOperationException(e);
}
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class WorkflowOperationWorker method resume.
/**
* Resumes a previously suspended workflow operation. Note that only workflow operation handlers that implement
* {@link ResumableWorkflowOperationHandler} can be resumed.
*
* @return the workflow operation result
* @throws WorkflowOperationException
* if executing the workflow operation handler fails
* @throws WorkflowException
* if there is a problem processing the workflow
* @throws IllegalStateException
* if the workflow operation cannot be resumed
*/
public WorkflowOperationResult resume() throws WorkflowOperationException, WorkflowException, IllegalStateException, UnauthorizedException {
WorkflowOperationInstance operation = workflow.getCurrentOperation();
// Make sure we have a (suitable) handler
if (handler == null) {
// If there is no handler for the operation, yet we are supposed to run it, we must fail
logger.warn("No handler available to resume operation '{}'", operation.getTemplate());
throw new IllegalStateException("Unable to find a workflow handler for '" + operation.getTemplate() + "'");
} else if (!(handler instanceof ResumableWorkflowOperationHandler)) {
throw new IllegalStateException("An attempt was made to resume a non-resumable operation");
}
ResumableWorkflowOperationHandler resumableHandler = (ResumableWorkflowOperationHandler) handler;
operation.setState(OperationState.RUNNING);
service.update(workflow);
try {
WorkflowOperationResult result = resumableHandler.resume(workflow, null, properties);
return result;
} catch (Exception e) {
operation.setState(OperationState.FAILED);
if (e instanceof WorkflowOperationException)
throw (WorkflowOperationException) e;
throw new WorkflowOperationException(e);
}
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class VideoEditorWorkflowOperationHandler method resume.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.ResumableWorkflowOperationHandler#resume(org.opencastproject.workflow.api.WorkflowInstance,
* JobContext, java.util.Map)
*/
@Override
public WorkflowOperationResult resume(WorkflowInstance workflowInstance, JobContext context, Map<String, String> properties) throws WorkflowOperationException {
MediaPackage mp = workflowInstance.getMediaPackage();
logger.info("Resume video editor operation for mediapackage {}", mp.getIdentifier().compact());
// Get configuration
WorkflowOperationInstance worflowOperationInstance = workflowInstance.getCurrentOperation();
String sourceTrackFlavorsProperty = StringUtils.trimToNull(worflowOperationInstance.getConfiguration(SOURCE_FLAVORS_PROPERTY));
if (sourceTrackFlavorsProperty == null) {
throw new WorkflowOperationException(format("Required configuration property %s not set.", SOURCE_FLAVORS_PROPERTY));
}
String targetSmilFlavorProperty = StringUtils.trimToNull(worflowOperationInstance.getConfiguration(TARGET_SMIL_FLAVOR_PROPERTY));
if (targetSmilFlavorProperty == null) {
throw new WorkflowOperationException(format("Required configuration property %s not set.", TARGET_SMIL_FLAVOR_PROPERTY));
}
String targetFlavorSybTypeProperty = StringUtils.trimToNull(worflowOperationInstance.getConfiguration(TARGET_FLAVOR_SUBTYPE_PROPERTY));
if (targetFlavorSybTypeProperty == null) {
throw new WorkflowOperationException(format("Required configuration property %s not set.", TARGET_FLAVOR_SUBTYPE_PROPERTY));
}
boolean skipIfNoTrim = BooleanUtils.toBoolean(worflowOperationInstance.getConfiguration(SKIP_NOT_TRIMMED_PROPERTY));
// Get source tracks
TrackSelector trackSelector = new TrackSelector();
for (String flavor : asList(sourceTrackFlavorsProperty)) {
trackSelector.addFlavor(flavor);
}
Collection<Track> sourceTracks = trackSelector.select(mp, false);
if (sourceTracks.isEmpty()) {
throw new WorkflowOperationException(format("No source tracks found in mediapacksge %s with flavors %s.", mp.getIdentifier().compact(), sourceTrackFlavorsProperty));
}
// Get SMIL file
MediaPackageElementFlavor smilTargetFlavor = MediaPackageElementFlavor.parseFlavor(targetSmilFlavorProperty);
Catalog[] smilCatalogs = mp.getCatalogs(smilTargetFlavor);
if (smilCatalogs == null || smilCatalogs.length == 0) {
throw new WorkflowOperationException(format("No SMIL catalog found in mediapackage %s with flavor %s.", mp.getIdentifier().compact(), targetSmilFlavorProperty));
}
File smilFile = null;
Smil smil = null;
try {
smilFile = workspace.get(smilCatalogs[0].getURI());
smil = smilService.fromXml(smilFile).getSmil();
smil = replaceAllTracksWith(smil, sourceTracks.toArray(new Track[sourceTracks.size()]));
InputStream is = null;
try {
is = IOUtils.toInputStream(smil.toXML(), "UTF-8");
// Remove old SMIL
workspace.delete(mp.getIdentifier().compact(), smilCatalogs[0].getIdentifier());
mp.remove(smilCatalogs[0]);
// put modified SMIL into workspace
URI newSmilUri = workspace.put(mp.getIdentifier().compact(), smil.getId(), SMIL_FILE_NAME, is);
Catalog catalog = (Catalog) MediaPackageElementBuilderFactory.newInstance().newElementBuilder().elementFromURI(newSmilUri, MediaPackageElement.Type.Catalog, smilCatalogs[0].getFlavor());
catalog.setIdentifier(smil.getId());
mp.add(catalog);
} catch (Exception ex) {
throw new WorkflowOperationException(ex);
} finally {
IOUtils.closeQuietly(is);
}
} catch (NotFoundException ex) {
throw new WorkflowOperationException(format("Failed to get SMIL catalog %s from mediapackage %s.", smilCatalogs[0].getIdentifier(), mp.getIdentifier().compact()), ex);
} catch (IOException ex) {
throw new WorkflowOperationException(format("Can't open SMIL catalog %s from mediapackage %s.", smilCatalogs[0].getIdentifier(), mp.getIdentifier().compact()), ex);
} catch (SmilException ex) {
throw new WorkflowOperationException(ex);
}
if (skipIfNoTrim) {
// We should not modify the SMIL file as we traverse through its elements, so we make a copy and modify it instead
try {
Smil filteredSmil = smilService.fromXml(smil.toXML()).getSmil();
for (SmilMediaObject element : smil.getBody().getMediaElements()) {
// body should contain par elements
if (element.isContainer()) {
SmilMediaContainer container = (SmilMediaContainer) element;
if (SmilMediaContainer.ContainerType.PAR == container.getContainerType()) {
continue;
}
}
filteredSmil = smilService.removeSmilElement(filteredSmil, element.getId()).getSmil();
}
// one that takes the whole video size
switch(filteredSmil.getBody().getMediaElements().size()) {
case 0:
logger.info("Skipping SMIL job generation for mediapackage '{}', " + "because the SMIL does not define any trimming points", mp.getIdentifier());
return skip(workflowInstance, context);
case 1:
// component represents the whole duration or not, therefore we don't bother to try
if (mp.getDuration() < 0)
break;
SmilMediaContainer parElement = (SmilMediaContainer) filteredSmil.getBody().getMediaElements().get(0);
boolean skip = true;
for (SmilMediaObject elementChild : parElement.getElements()) {
if (!elementChild.isContainer()) {
SmilMediaElement media = (SmilMediaElement) elementChild;
// If they don't represent the whole length, then we break --we have a trimming point
if ((media.getClipBeginMS() != 0) || (media.getClipEndMS() != mp.getDuration())) {
skip = false;
break;
}
}
}
if (skip) {
logger.info("Skipping SMIL job generation for mediapackage '{}', " + "because the trimming points in the SMIL correspond " + "to the beginning and the end of the video", mp.getIdentifier());
return skip(workflowInstance, context);
}
break;
default:
break;
}
} catch (MalformedURLException | SmilException | JAXBException | SAXException e) {
logger.warn("Error parsing input SMIL to determine if it has trimpoints. " + "We will assume it does and go on creating jobs.");
}
}
// Create video edit jobs and run them
List<Job> jobs = null;
try {
logger.info("Create processing jobs for SMIL file: {}", smilCatalogs[0].getIdentifier());
jobs = videoEditorService.processSmil(smil);
if (!waitForStatus(jobs.toArray(new Job[jobs.size()])).isSuccess()) {
throw new WorkflowOperationException(format("Processing SMIL file failed: %s", smilCatalogs[0].getIdentifier()));
}
logger.info("Finished processing of SMIL file: {}", smilCatalogs[0].getIdentifier());
} catch (ProcessFailedException ex) {
throw new WorkflowOperationException(format("Finished processing of SMIL file: %s", smilCatalogs[0].getIdentifier()), ex);
}
// Move edited tracks to work location and set target flavor
Track editedTrack = null;
boolean mpAdded = false;
for (Job job : jobs) {
try {
editedTrack = (Track) MediaPackageElementParser.getFromXml(job.getPayload());
MediaPackageElementFlavor editedTrackFlavor = editedTrack.getFlavor();
editedTrack.setFlavor(new MediaPackageElementFlavor(editedTrackFlavor.getType(), targetFlavorSybTypeProperty));
URI editedTrackNewUri = workspace.moveTo(editedTrack.getURI(), mp.getIdentifier().compact(), editedTrack.getIdentifier(), FilenameUtils.getName(editedTrack.getURI().toString()));
editedTrack.setURI(editedTrackNewUri);
for (Track track : sourceTracks) {
if (track.getFlavor().getType().equals(editedTrackFlavor.getType())) {
mp.addDerived(editedTrack, track);
mpAdded = true;
break;
}
}
if (!mpAdded) {
mp.add(editedTrack);
}
} catch (MediaPackageException ex) {
throw new WorkflowOperationException("Failed to get information about the edited track(s)", ex);
} catch (NotFoundException | IOException | IllegalArgumentException ex) {
throw new WorkflowOperationException("Moving edited track to work location failed.", ex);
} catch (Exception ex) {
throw new WorkflowOperationException(ex);
}
}
logger.info("VideoEdit workflow {} finished", workflowInstance.getId());
return createResult(mp, Action.CONTINUE);
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class LoggingWorkflowOperationHandler method saveOrLog.
/**
* Log data to directory if set, otherwise use the system logger.
*
* @param data
* Data to log
* @param directory
* Directory to log to. If set to null, the default logger is used.
* @param filename
* Filename to write the data to. Used by internal logger as well.
* @throws WorkflowOperationException
* In case the data could not be written
*/
private void saveOrLog(final String data, final File directory, final String filename) throws WorkflowOperationException {
// Write to directory if set
if (directory != null) {
File file = new File(directory, filename);
try {
logger.info("Logging current workflow state to to {}", file.getAbsolutePath());
FileUtils.writeStringToFile(file, data, Charset.defaultCharset());
} catch (IOException e) {
throw new WorkflowOperationException(e);
}
} else {
// …otherwise, just use the logger
logger.info("({}):\n{}", filename, data);
}
}
use of org.opencastproject.workflow.api.WorkflowOperationException in project opencast by opencast.
the class LoggingWorkflowOperationHandler 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 {
WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
String directoryPath = StringUtils.trimToNull(operation.getConfiguration("directory"));
File directory = null;
if (directoryPath != null) {
directory = new File(directoryPath);
try {
FileUtils.forceMkdir(directory);
} catch (IOException e) {
throw new WorkflowOperationException(String.format("Failed to create output directory '%s'", directoryPath), e);
}
}
boolean logMediaPackageJSON = BooleanUtils.toBoolean(operation.getConfiguration("mediapackage-json"));
boolean logMediaPackageXML = BooleanUtils.toBoolean(operation.getConfiguration("mediapackage-xml"));
boolean logWorkflowInstance = BooleanUtils.toBoolean(operation.getConfiguration("workflowinstance-xml"));
if (!(logMediaPackageJSON || logMediaPackageXML || logWorkflowInstance)) {
logMediaPackageJSON = true;
}
MediaPackage mediaPackage = workflowInstance.getMediaPackage();
// Log media package as JSON
if (logMediaPackageJSON) {
String filename = String.format("workflow-%d-%d-mediapackage-%s.json", workflowInstance.getId(), operation.getId(), mediaPackage.getIdentifier());
saveOrLog(MediaPackageParser.getAsJSON(mediaPackage), directory, filename);
}
// Log media package as XML
if (logMediaPackageXML) {
String filename = String.format("workflow-%d-%d-mediapackage-%s.xml", workflowInstance.getId(), operation.getId(), mediaPackage.getIdentifier());
saveOrLog(MediaPackageParser.getAsXml(mediaPackage), directory, filename);
}
// Log workflow instance as XML
if (logWorkflowInstance) {
String filename = String.format("workflow-%d-%d.xml", workflowInstance.getId(), operation.getId());
try {
saveOrLog(WorkflowParser.toXml(workflowInstance), directory, filename);
} catch (WorkflowParsingException e) {
throw new WorkflowOperationException(e);
}
}
// Continue with unmodified media package
return createResult(mediaPackage, Action.CONTINUE);
}
Aggregations