use of org.opencastproject.workflow.api.WorkflowInstance in project opencast by opencast.
the class ExportWorkflowPropertiesWOHTest method testExport.
@Test
public void testExport() throws Exception {
final WorkflowOperationInstance woi = createMock(WorkflowOperationInstance.class);
expect(woi.getConfiguration("target-flavor")).andStubReturn(FLAVOR);
expect(woi.getConfiguration("target-tags")).andStubReturn("archive");
expect(woi.getConfiguration("keys")).andStubReturn("chapter,presenter_position");
replay(woi);
final Attachment att = new AttachmentImpl();
att.setURI(uri);
att.setFlavor(MediaPackageElementFlavor.parseFlavor(FLAVOR));
final MediaPackage mp = MediaPackageBuilderFactory.newInstance().newMediaPackageBuilder().createNew();
mp.add(att);
WorkflowInstance wi = createMock(WorkflowInstance.class);
expect(wi.getCurrentOperation()).andStubReturn(woi);
expect(wi.getMediaPackage()).andStubReturn(mp);
Set<String> keys = new HashSet<>();
keys.add("presenter_position");
keys.add("cover_marker_in_s");
expect(wi.getConfigurationKeys()).andStubReturn(keys);
expect(wi.getConfiguration("presenter_position")).andStubReturn("right");
expect(wi.getConfiguration("cover_marker_in_s")).andStubReturn("30.674");
replay(wi);
final ExportWorkflowPropertiesWOH woh = new ExportWorkflowPropertiesWOH();
woh.setWorkspace(workspace);
WorkflowOperationResult result = woh.start(wi, null);
Attachment[] attachments = result.getMediaPackage().getAttachments();
Assert.assertTrue(attachments.length == 1);
Attachment attachment = attachments[0];
assertEquals("processing/defaults", attachment.getFlavor().toString());
assertEquals("archive", attachment.getTags()[0]);
Assert.assertNotNull(attachment.getURI());
File file = workspace.get(attachment.getURI());
Properties props = new Properties();
try (InputStream is = new FileInputStream(file)) {
props.loadFromXML(is);
}
assertEquals("30.674", props.get("cover_marker_in_s"));
assertEquals("right", props.get("presenter_position"));
Assert.assertFalse(props.contains("chapter"));
verify(wi);
}
use of org.opencastproject.workflow.api.WorkflowInstance in project opencast by opencast.
the class ProbeResolutionWorkflowOperationHandlerTest method testStart.
@Test
public void testStart() throws MediaPackageException, WorkflowOperationException {
MediaPackage mediaPackage = MediaPackageBuilderFactory.newInstance().newMediaPackageBuilder().createNew();
VideoStreamImpl videoStream = new VideoStreamImpl("234");
videoStream.setFrameWidth(1280);
videoStream.setFrameHeight(720);
TrackImpl track = new TrackImpl();
track.setFlavor(MediaPackageElementFlavor.parseFlavor("presenter/source"));
track.addStream(videoStream);
JobContext jobContext = EasyMock.createMock(JobContext.class);
EasyMock.replay(jobContext);
WorkflowOperationInstance operationInstance = EasyMock.createMock(WorkflowOperationInstance.class);
String[][] config = { { ProbeResolutionWorkflowOperationHandler.OPT_SOURCE_FLAVOR, "*/source" }, { ProbeResolutionWorkflowOperationHandler.OPT_VAR_PREFIX + "aspect", "1280x720,1280x700" }, { ProbeResolutionWorkflowOperationHandler.OPT_VAL_PREFIX + "aspect", "16/9" }, { ProbeResolutionWorkflowOperationHandler.OPT_VAR_PREFIX + "is_720", "1280x720,1280x700" }, { ProbeResolutionWorkflowOperationHandler.OPT_VAR_PREFIX + "is_1080", "1920x1080" } };
Set<String> keys = new HashSet<>();
for (String[] cfg : config) {
keys.add(cfg[0]);
EasyMock.expect(operationInstance.getConfiguration(cfg[0])).andReturn(cfg[1]).anyTimes();
}
EasyMock.expect(operationInstance.getConfigurationKeys()).andReturn(keys).anyTimes();
EasyMock.replay(operationInstance);
WorkflowInstance workflowInstance = EasyMock.createMock(WorkflowInstance.class);
EasyMock.expect(workflowInstance.getMediaPackage()).andReturn(mediaPackage).anyTimes();
EasyMock.expect(workflowInstance.getCurrentOperation()).andReturn(operationInstance).anyTimes();
EasyMock.replay(workflowInstance);
// With no matching track
assertEquals(null, operationHandler.start(workflowInstance, jobContext).getProperties());
// With matching track
mediaPackage.add(track);
WorkflowOperationResult workflowOperationResult = operationHandler.start(workflowInstance, jobContext);
Map<String, String> properties = workflowOperationResult.getProperties();
String[][] props = { { "presenter_source_aspect", "16/9" }, { "presenter_source_is_720", "true" }, { "presenter_source_is_1080", null } };
for (String[] prop : props) {
assertEquals(prop[1], properties.get(prop[0]));
}
}
use of org.opencastproject.workflow.api.WorkflowInstance in project opencast by opencast.
the class WorkflowServiceImpl method cleanupWorkflowInstances.
@Override
public synchronized void cleanupWorkflowInstances(int buffer, WorkflowState state) throws UnauthorizedException, WorkflowDatabaseException {
logger.info("Start cleaning up workflow instances older than {} days with status '{}'", buffer, state);
int instancesCleaned = 0;
int cleaningFailed = 0;
WorkflowQuery query = new WorkflowQuery().withState(state).withDateBefore(DateUtils.addDays(new Date(), -buffer)).withCount(Integer.MAX_VALUE);
for (WorkflowInstance workflowInstance : getWorkflowInstances(query).getItems()) {
try {
remove(workflowInstance.getId());
instancesCleaned++;
} catch (WorkflowDatabaseException e) {
throw e;
} catch (UnauthorizedException e) {
throw e;
} catch (NotFoundException e) {
// Since we are in a cleanup operation, we don't have to care about NotFoundExceptions
logger.debug("Workflow instance '{}' could not be removed: {}", workflowInstance.getId(), ExceptionUtils.getStackTrace(e));
} catch (WorkflowParsingException e) {
logger.warn("Workflow instance '{}' could not be removed: {}", workflowInstance.getId(), ExceptionUtils.getStackTrace(e));
cleaningFailed++;
} catch (WorkflowStateException e) {
logger.warn("Workflow instance '{}' could not be removed: {}", workflowInstance.getId(), ExceptionUtils.getStackTrace(e));
cleaningFailed++;
}
}
if (instancesCleaned == 0 && cleaningFailed == 0) {
logger.info("No workflow instances found to clean up");
return;
}
if (instancesCleaned > 0)
logger.info("Cleaned up '%d' workflow instances", instancesCleaned);
if (cleaningFailed > 0) {
logger.warn("Cleaning failed for '%d' workflow instances", cleaningFailed);
throw new WorkflowDatabaseException("Unable to clean all workflow instances, see logs!");
}
}
use of org.opencastproject.workflow.api.WorkflowInstance in project opencast by opencast.
the class WorkflowServiceImpl method remove.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowService#remove(long)
*/
@Override
public void remove(long workflowInstanceId) throws WorkflowDatabaseException, NotFoundException, UnauthorizedException, WorkflowParsingException, WorkflowStateException {
final Lock lock = this.lock.get(workflowInstanceId);
lock.lock();
try {
WorkflowQuery query = new WorkflowQuery();
query.withId(Long.toString(workflowInstanceId));
WorkflowSet workflows = index.getWorkflowInstances(query, Permissions.Action.READ.toString(), false);
if (workflows.size() == 1) {
WorkflowInstance instance = workflows.getItems()[0];
WorkflowInstance.WorkflowState state = instance.getState();
if (state != WorkflowState.SUCCEEDED && state != WorkflowState.FAILED && state != WorkflowState.STOPPED)
throw new WorkflowStateException("Workflow instance with state '" + state + "' cannot be removed. Only states SUCCEEDED, FAILED & STOPPED are allowed");
try {
assertPermission(instance, Permissions.Action.WRITE.toString());
} catch (MediaPackageException e) {
throw new WorkflowParsingException(e);
}
// First, remove temporary files DO THIS BEFORE REMOVING FROM INDEX
try {
removeTempFiles(instance);
} catch (NotFoundException e) {
// If the files aren't their anymore, we don't have to cleanup up them :-)
logger.debug("Temporary files of workflow instance %d seem to be gone already...", workflowInstanceId);
}
// Second, remove jobs related to a operation which belongs to the workflow instance
List<WorkflowOperationInstance> operations = instance.getOperations();
List<Long> jobsToDelete = new ArrayList<>();
for (WorkflowOperationInstance op : operations) {
if (op.getId() != null) {
long workflowOpId = op.getId();
if (workflowOpId != workflowInstanceId) {
jobsToDelete.add(workflowOpId);
}
}
}
try {
serviceRegistry.removeJobs(jobsToDelete);
} catch (ServiceRegistryException e) {
logger.warn("Problems while removing jobs related to workflow operations '%s': %s", jobsToDelete, e.getMessage());
} catch (NotFoundException e) {
logger.debug("No jobs related to one of the workflow operations '%s' found in the service registry", jobsToDelete);
}
// Third, remove workflow instance job itself
try {
serviceRegistry.removeJobs(Collections.singletonList(workflowInstanceId));
messageSender.sendObjectMessage(WorkflowItem.WORKFLOW_QUEUE, MessageSender.DestinationType.Queue, WorkflowItem.deleteInstance(workflowInstanceId, instance));
} catch (ServiceRegistryException e) {
logger.warn("Problems while removing workflow instance job '%d': %s", workflowInstanceId, ExceptionUtils.getStackTrace(e));
} catch (NotFoundException e) {
logger.info("No workflow instance job '%d' found in the service registry", workflowInstanceId);
}
// At last, remove workflow instance from the index
try {
index.remove(workflowInstanceId);
} catch (NotFoundException e) {
// This should never happen, because we got workflow instance by querying the index...
logger.warn("Workflow instance could not be removed from index: %s", ExceptionUtils.getStackTrace(e));
}
} else if (workflows.size() == 0) {
throw new NotFoundException("Workflow instance with id '" + Long.toString(workflowInstanceId) + "' could not be found");
} else {
throw new WorkflowDatabaseException("More than one workflow found with id: " + Long.toString(workflowInstanceId));
}
} finally {
lock.unlock();
}
}
use of org.opencastproject.workflow.api.WorkflowInstance in project opencast by opencast.
the class WorkflowServiceImpl method resume.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowService#resume(long, Map)
*/
@Override
public WorkflowInstance resume(long workflowInstanceId, Map<String, String> properties) throws WorkflowException, NotFoundException, IllegalStateException, UnauthorizedException {
WorkflowInstance workflowInstance = getWorkflowById(workflowInstanceId);
if (!WorkflowState.PAUSED.equals(workflowInstance.getState()))
throw new IllegalStateException("Can not resume a workflow where the current state is not in paused");
workflowInstance = updateConfiguration(workflowInstance, properties);
update(workflowInstance);
WorkflowOperationInstance currentOperation = workflowInstance.getCurrentOperation();
// Is the workflow done?
if (currentOperation == null) {
// Let's make sure we didn't miss any failed operation, since the workflow state could have been
// switched to paused while processing the error handling workflow extension
workflowInstance.setState(SUCCEEDED);
for (WorkflowOperationInstance op : workflowInstance.getOperations()) {
if (op.getState().equals(WorkflowOperationInstance.OperationState.FAILED)) {
if (op.isFailWorkflowOnException()) {
workflowInstance.setState(FAILED);
break;
}
}
}
// Save the resumed workflow to the database
logger.debug("%s has %s", workflowInstance, workflowInstance.getState());
update(workflowInstance);
return workflowInstance;
}
// certain operations. In the latter case, there is no current paused operation.
if (OperationState.INSTANTIATED.equals(currentOperation.getState())) {
try {
// the operation has its own job. Update that too.
Job operationJob = serviceRegistry.createJob(JOB_TYPE, Operation.START_OPERATION.toString(), Arrays.asList(Long.toString(workflowInstanceId)), null, false, null, WORKFLOW_JOB_LOAD);
// this method call is publicly visible, so it doesn't necessarily go through the accept method. Set the
// workflow state manually.
workflowInstance.setState(RUNNING);
currentOperation.setId(operationJob.getId());
// update the workflow and its associated job
update(workflowInstance);
// Now set this job to be queued so it can be dispatched
operationJob.setStatus(Status.QUEUED);
operationJob.setDispatchable(true);
operationJob = serviceRegistry.updateJob(operationJob);
return workflowInstance;
} catch (ServiceRegistryException e) {
throw new WorkflowDatabaseException(e);
}
}
Long operationJobId = workflowInstance.getCurrentOperation().getId();
if (operationJobId == null)
throw new IllegalStateException("Can not resume a workflow where the current operation has no associated id");
// Set the current operation's job to queued, so it gets picked up again
Job workflowJob;
try {
workflowJob = serviceRegistry.getJob(workflowInstanceId);
workflowJob.setStatus(Status.RUNNING);
workflowJob.setPayload(WorkflowParser.toXml(workflowInstance));
workflowJob = serviceRegistry.updateJob(workflowJob);
Job operationJob = serviceRegistry.getJob(operationJobId);
operationJob.setStatus(Status.QUEUED);
operationJob.setDispatchable(true);
if (properties != null) {
Properties props = new Properties();
props.putAll(properties);
ByteArrayOutputStream out = new ByteArrayOutputStream();
props.store(out, null);
List<String> newArguments = new ArrayList<String>(operationJob.getArguments());
newArguments.add(new String(out.toByteArray(), "UTF-8"));
operationJob.setArguments(newArguments);
}
operationJob = serviceRegistry.updateJob(operationJob);
} catch (ServiceRegistryException e) {
throw new WorkflowDatabaseException(e);
} catch (IOException e) {
throw new WorkflowParsingException("Unable to parse workflow and/or workflow properties");
}
return workflowInstance;
}
Aggregations