use of org.onosproject.workflow.api.ProgramCounter in project onos by opennetworkinglab.
the class WorkFlowEngine method execWorkflowContext.
/**
* Executes workflow context.
*
* @param context workflow context
* @return workflow context
*/
private WorkflowContext execWorkflowContext(WorkflowContext context) {
Workflow workflow = workflowStore.get(context.workflowId());
if (workflow == null) {
log.error("Invalid workflow {}", context.workflowId());
return null;
}
final WorkflowContext latestContext = workplaceStore.getContext(context.name());
if (latestContext == null) {
log.error("Invalid workflow context {}", context.name());
return null;
}
initWorkletExecution(latestContext);
try {
final ProgramCounter pc = workflow.next(latestContext);
final Worklet worklet = workflow.getWorkletInstance(pc);
if (worklet == Worklet.Common.INIT) {
log.error("workflow.next gave INIT. It cannot be executed (context: {})", context.name());
return latestContext;
}
latestContext.setCurrent(pc);
if (worklet == Worklet.Common.COMPLETED) {
if (workflow.attributes().contains(REMOVE_AFTER_COMPLETE)) {
workplaceStore.removeContext(latestContext.name());
return null;
} else {
latestContext.setState(WorkflowState.IDLE);
workplaceStore.commitContext(latestContext.name(), latestContext, false);
return latestContext;
}
}
log.info("{} worklet.process:{}", latestContext.name(), worklet.tag());
log.trace("{} context: {}", latestContext.name(), latestContext);
dataModelInjector.inject(worklet, latestContext);
WorkletDescription workletDesc = workflow.getWorkletDesc(pc);
if (Objects.nonNull(workletDesc)) {
if (!(workletDesc.tag().equals("INIT") || workletDesc.tag().equals("COMPLETED"))) {
staticDataModelInjector.inject(worklet, workletDesc);
}
}
worklet.process(latestContext);
dataModelInjector.inhale(worklet, latestContext);
log.info("{} worklet.process(done): {}", latestContext.name(), worklet.tag());
log.trace("{} context: {}", latestContext.name(), latestContext);
if (latestContext.completionEventType() != null) {
if (latestContext.completionEventGenerator() == null) {
String msg = String.format("Invalid exepecting event(%s), generator(%s)", latestContext.completionEventType(), latestContext.completionEventGenerator());
throw new WorkflowException(msg);
}
registerEventMap(latestContext.completionEventType(), latestContext.completionEventHints(), latestContext.name(), pc.toString());
latestContext.completionEventGenerator().apply();
if (latestContext.completionEventTimeout() != 0L) {
final EventTimeoutTask eventTimeoutTask = EventTimeoutTask.builder().context(latestContext).programCounter(pc).eventType(latestContext.completionEventType().getName()).eventHintSet(latestContext.completionEventHints()).build();
timerChain.schedule(latestContext.completionEventTimeout(), () -> {
eventtaskAccumulator.add(eventTimeoutTask);
});
}
} else {
if (latestContext.completionEventTimeout() != 0L) {
final TimeoutTask timeoutTask = TimeoutTask.builder().context(latestContext).programCounter(pc).build();
timerChain.schedule(latestContext.completionEventTimeout(), () -> {
eventtaskAccumulator.add(timeoutTask);
});
} else {
// completed case
// increase program counter
latestContext.setCurrent(workflow.increased(pc));
}
}
workplaceStore.commitContext(latestContext.name(), latestContext, latestContext.triggerNext());
} catch (WorkflowException e) {
log.error("Exception: ", e);
latestContext.setCause(e.getMessage());
latestContext.setState(WorkflowState.EXCEPTION);
workplaceStore.commitContext(latestContext.name(), latestContext, false);
} catch (StorageException e) {
log.error("Exception: ", e);
// StorageException does not commit context.
} catch (Exception e) {
log.error("Exception: ", e);
latestContext.setCause(e.getMessage());
latestContext.setState(WorkflowState.EXCEPTION);
workplaceStore.commitContext(latestContext.name(), latestContext, false);
}
return latestContext;
}
use of org.onosproject.workflow.api.ProgramCounter in project onos by opennetworkinglab.
the class WorkflowManager method checkWorkflowDataModelSchema.
/**
* Checks the schema of workflow data.
*
* @param workflow workflow
* @param worklowDescJson jsonNode
* @throws WorkflowException workflow exception
*/
private void checkWorkflowDataModelSchema(Workflow workflow, JsonNode worklowDescJson) throws WorkflowException {
List<String> errors = new ArrayList<>();
JsonNode dataNode = worklowDescJson.get("data");
if (Objects.isNull(dataNode) || dataNode instanceof MissingNode) {
errors.add("workflow description json does not have 'data'");
throw new WorkflowDataModelException(workflow.id(), worklowDescJson, errors);
}
for (ProgramCounter pc : workflow.getProgram()) {
Worklet worklet = workflow.getWorkletInstance(pc);
if (Worklet.Common.COMPLETED.equals(worklet) || Worklet.Common.INIT.equals(worklet)) {
continue;
}
Class cls = worklet.getClass();
for (Field field : cls.getDeclaredFields()) {
if (field.isSynthetic()) {
continue;
}
for (Annotation annotation : field.getAnnotations()) {
if (!(annotation instanceof JsonDataModel)) {
continue;
}
JsonDataModel jsonDataModel = (JsonDataModel) annotation;
Matcher matcher = Pattern.compile("(\\w+)").matcher(jsonDataModel.path());
if (!matcher.find()) {
throw new WorkflowException("Invalid Json Data Model Path(" + jsonDataModel.path() + ") in " + worklet.tag());
}
String path = matcher.group(1);
Optional<String> optError = getJsonNodeDataError(dataNode, worklet, field, path, jsonDataModel.optional());
if (optError.isPresent()) {
errors.add(optError.get());
}
}
}
}
if (!errors.isEmpty()) {
throw new WorkflowDataModelException(workflow.id(), worklowDescJson, errors);
}
}
use of org.onosproject.workflow.api.ProgramCounter in project onos by opennetworkinglab.
the class WorkFlowEngine method eventMapTrigger.
@Override
public void eventMapTrigger(Event event, EventHintSupplier supplier) {
if (event.subject() instanceof SystemWorkflowContext) {
return;
}
Map<String, String> eventMap;
String eventHint;
try {
eventHint = supplier.apply(event);
} catch (Throwable e) {
log.error("Exception: ", e);
return;
}
if (eventHint == null) {
// do nothing
log.error("Invalid eventHint, event: {}", event);
return;
}
try {
eventMap = eventMapStore.getEventMapByHint(event.getClass().getName(), eventHint);
} catch (WorkflowException e) {
log.error("Exception: ", e);
return;
}
if (Objects.isNull(eventMap) || eventMap.isEmpty()) {
// do nothing;
log.debug("Invalid eventMap, event: {}", event);
return;
}
for (Map.Entry<String, String> entry : eventMap.entrySet()) {
String contextName = entry.getKey();
String strProgramCounter = entry.getValue();
ProgramCounter pc;
try {
pc = ProgramCounter.valueOf(strProgramCounter);
} catch (IllegalArgumentException e) {
log.error("Exception: ", e);
return;
}
WorkflowContext context = workplaceStore.getContext(contextName);
if (Objects.isNull(context)) {
log.info("Invalid context: {}, event: {}", contextName, event);
continue;
}
EventTask eventtask = null;
try {
eventtask = EventTask.builder().event(event).eventHint(eventHint).context(context).programCounter(pc).build();
} catch (WorkflowException e) {
log.error("Exception: ", e);
}
log.debug("eventtaskAccumulator.add: task: {}", eventtask);
if (!Objects.isNull(eventtask)) {
eventtaskAccumulator.add(eventtask);
}
}
}
use of org.onosproject.workflow.api.ProgramCounter in project onos by opennetworkinglab.
the class WorkFlowEngine method execEventTask.
/**
* Executes event task.
*
* @param task event task
* @return event task
*/
private EventTask execEventTask(EventTask task) {
if (!eventMapStore.isEventMapPresent(task.context().name())) {
log.trace("EventMap doesnt exist for taskcontext:{}", task.context().name());
return task;
}
log.debug("execEventTask- task: {}, hash: {}", task, stringHash(task.context().distributor()));
WorkflowContext context = (WorkflowContext) (task.context());
Workflow workflow = workflowStore.get(context.workflowId());
if (workflow == null) {
log.error("Invalid workflow {}", context.workflowId());
return task;
}
WorkflowContext latestContext = workplaceStore.getContext(context.name());
if (latestContext == null) {
log.error("Invalid workflow context {}", context.name());
return task;
}
try {
if (!Objects.equals(latestContext.current(), task.programCounter())) {
log.error("Current worklet({}) is not mismatched with task work({}). Ignored.", latestContext.current(), task.programCounter());
return task;
}
Worklet worklet = workflow.getWorkletInstance(task.programCounter());
if (Worklet.Common.COMPLETED.equals(worklet) || Worklet.Common.INIT.equals(worklet)) {
log.error("Current worklet is {}, Ignored", worklet);
return task;
}
initWorkletExecution(latestContext);
log.info("{} worklet.isCompleted:{}", latestContext.name(), worklet.tag());
log.trace("{} task:{}, context: {}", latestContext.name(), task, latestContext);
dataModelInjector.inject(worklet, latestContext);
boolean completed = worklet.isCompleted(latestContext, task.event());
dataModelInjector.inhale(worklet, latestContext);
if (completed) {
log.info("{} worklet.isCompleted(true):{}", latestContext.name(), worklet.tag());
log.trace("{} task:{}, context: {}", latestContext.name(), task, latestContext);
eventMapStore.unregisterEventMap(task.eventType(), latestContext.name());
// completed case
// increase program counter
ProgramCounter pc = latestContext.current();
latestContext.setCurrent(workflow.increased(pc));
workplaceStore.commitContext(latestContext.name(), latestContext, true);
return null;
} else {
log.info("{} worklet.isCompleted(false):{}", latestContext.name(), worklet.tag());
log.trace("{} task:{}, context: {}", latestContext.name(), task, latestContext);
workplaceStore.commitContext(latestContext.name(), latestContext, false);
}
} catch (WorkflowException e) {
log.error("Exception: ", e);
latestContext.setCause(e.getMessage());
latestContext.setState(WorkflowState.EXCEPTION);
workplaceStore.commitContext(latestContext.name(), latestContext, false);
} catch (StorageException e) {
log.error("Exception: ", e);
// StorageException does not commit context.
} catch (Exception e) {
log.error("Exception: ", e);
latestContext.setCause(e.getMessage());
latestContext.setState(WorkflowState.EXCEPTION);
workplaceStore.commitContext(latestContext.name(), latestContext, false);
}
return task;
}
use of org.onosproject.workflow.api.ProgramCounter in project onos by opennetworkinglab.
the class WorkflowManager method checkWorkflow.
/**
* Checks the validity of workflow definition.
* @param workflow workflow to be checked
* @throws WorkflowException workflow exception
*/
private void checkWorkflow(Workflow workflow) throws WorkflowException {
Map<String, WorkletDataModelFieldDesc> descMap = new HashMap<>();
List<String> errors = new ArrayList<>();
for (ProgramCounter pc : workflow.getProgram()) {
Worklet worklet = workflow.getWorkletInstance(pc);
if (Worklet.Common.COMPLETED.equals(worklet) || Worklet.Common.INIT.equals(worklet)) {
continue;
}
Class cls = worklet.getClass();
for (Field field : cls.getDeclaredFields()) {
if (field.isSynthetic()) {
continue;
}
for (Annotation annotation : field.getAnnotations()) {
if (!(annotation instanceof JsonDataModel)) {
continue;
}
JsonDataModel jsonDataModel = (JsonDataModel) annotation;
Matcher matcher = Pattern.compile("(\\w+)").matcher(jsonDataModel.path());
if (!matcher.find()) {
throw new WorkflowException("Invalid Json Data Model Path(" + jsonDataModel.path() + ") in " + worklet.tag());
}
String path = matcher.group(1);
WorkletDataModelFieldDesc desc = new WorkletDataModelFieldDesc(pc.workletType(), path, field.getType(), jsonDataModel.optional());
WorkletDataModelFieldDesc existing = descMap.get(path);
if (Objects.isNull(existing)) {
descMap.put(path, desc);
} else {
if (!desc.hasSameAttributes(existing)) {
errors.add("" + desc + " is conflicted with " + existing + " in workflow " + workflow.id());
}
}
}
}
}
if (!errors.isEmpty()) {
throw new WorkflowDefinitionException(workflow.id(), errors);
}
}
Aggregations