mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 12:16:13 +02:00
workflow app fixes
Change-Id: Ia3b06b7947671e4e38ca37eb832e6a969ed1e6af
This commit is contained in:
parent
65cb23d676
commit
63a921cb33
@ -55,6 +55,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Constructor of ImmutableListWorkflow.
|
||||
*
|
||||
* @param builder builder of ImmutableListWorkflow
|
||||
*/
|
||||
private ImmutableListWorkflow(Builder builder) {
|
||||
@ -148,7 +149,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
WorkflowStore store;
|
||||
try {
|
||||
store = DefaultServiceDirectory.getService(WorkflowStore.class);
|
||||
store = DefaultServiceDirectory.getService(WorkflowStore.class);
|
||||
} catch (ServiceNotFoundException e) {
|
||||
throw new WorkflowException(e);
|
||||
}
|
||||
@ -179,8 +180,14 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
return ImmutableSet.copyOf(attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getWorkletTypeList() {
|
||||
return ImmutableList.copyOf(workletTypeList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets index of class in worklet type list.
|
||||
*
|
||||
* @param aClass class to get index
|
||||
* @return index of class in worklet type list
|
||||
*/
|
||||
@ -195,6 +202,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Checks whether class is allowed class or not.
|
||||
*
|
||||
* @param clazz class to check
|
||||
* @return Check result
|
||||
*/
|
||||
@ -245,6 +253,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Gets a instance of builder.
|
||||
*
|
||||
* @return instance of builder
|
||||
*/
|
||||
public static Builder builder() {
|
||||
@ -263,6 +272,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Sets id of immutable list workflow.
|
||||
*
|
||||
* @param uri id of immutable list workflow
|
||||
* @return builder
|
||||
*/
|
||||
@ -274,6 +284,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Sets init worklet class name of immutable list workflow.
|
||||
*
|
||||
* @param workletClassName class name of worklet
|
||||
* @return builder
|
||||
*/
|
||||
@ -284,6 +295,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Chains worklet class name of immutable list workflow.
|
||||
*
|
||||
* @param workletClassName class name of worklet
|
||||
* @return builder
|
||||
*/
|
||||
@ -294,6 +306,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Adds workflow attribute.
|
||||
*
|
||||
* @param attribute workflow attribute to be added
|
||||
* @return builder
|
||||
*/
|
||||
@ -304,6 +317,7 @@ public final class ImmutableListWorkflow extends AbstractWorkflow {
|
||||
|
||||
/**
|
||||
* Builds ImmutableListWorkflow.
|
||||
*
|
||||
* @return instance of ImmutableListWorkflow
|
||||
*/
|
||||
public ImmutableListWorkflow build() {
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.onosproject.workflow.api;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -84,4 +85,10 @@ public interface Workflow {
|
||||
* @return attributes
|
||||
*/
|
||||
Set<WorkflowAttribute> attributes();
|
||||
|
||||
/**
|
||||
* Returns worklet type list.
|
||||
* @return worklet type
|
||||
*/
|
||||
List<String> getWorkletTypeList();
|
||||
}
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2019-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.onosproject.workflow.api;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Workflow DataModel exception class.
|
||||
*/
|
||||
public class WorkflowDataModelException extends WorkflowException {
|
||||
|
||||
private String workflowName;
|
||||
private Map<String, Map<String, String>> errorListMap;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for Workflow DataModel Exception.
|
||||
*
|
||||
* @param msg exception message
|
||||
*/
|
||||
public WorkflowDataModelException(String msg) {
|
||||
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Workflow DataModel Exception.
|
||||
*
|
||||
* @param msg exception message
|
||||
* @param workflowName workflow name
|
||||
* @param errorListMap throwable to deliver
|
||||
*/
|
||||
public WorkflowDataModelException(String msg, String workflowName, Map<String, Map<String, String>> errorListMap) {
|
||||
super(msg);
|
||||
this.workflowName = workflowName;
|
||||
this.errorListMap = errorListMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WorkflowDataModelException{" +
|
||||
"workflowName='" + workflowName + '\'' +
|
||||
", errorListMap=" + errorListMap.toString() +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
@ -37,15 +37,16 @@ import java.util.Objects;
|
||||
public class WorkFlowTestCommand extends AbstractShellCommand {
|
||||
|
||||
static final String INVOKE_SAMPLE = "invoke-sample";
|
||||
static final String EXCEPTION_SAMPLE = "exception-sample";
|
||||
|
||||
@Argument(index = 0, name = "test-name",
|
||||
description = "Test name (" + INVOKE_SAMPLE + ")",
|
||||
description = "Test name (" + INVOKE_SAMPLE + " | " + EXCEPTION_SAMPLE + ")",
|
||||
required = true)
|
||||
@Completion(WorkFlowTestCompleter.class)
|
||||
private String testName = null;
|
||||
|
||||
@Argument(index = 1, name = "arg1",
|
||||
description = "number of test for " + INVOKE_SAMPLE,
|
||||
description = "number of test for (" + INVOKE_SAMPLE + " | " + EXCEPTION_SAMPLE + ")",
|
||||
required = false)
|
||||
private String arg1 = null;
|
||||
|
||||
@ -76,6 +77,26 @@ public class WorkFlowTestCommand extends AbstractShellCommand {
|
||||
|
||||
invokeSampleTest(num);
|
||||
break;
|
||||
|
||||
case EXCEPTION_SAMPLE:
|
||||
if (Objects.isNull(arg1)) {
|
||||
error("arg1 is required for test " + EXCEPTION_SAMPLE);
|
||||
return;
|
||||
}
|
||||
int count;
|
||||
try {
|
||||
count = Integer.parseInt(arg1);
|
||||
} catch (NumberFormatException e) {
|
||||
error("arg1 should be an integer value");
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
error(e.getMessage() + ", trace: " + Arrays.asList(e.getStackTrace()));
|
||||
return;
|
||||
}
|
||||
|
||||
invokeExceptionTest(count);
|
||||
break;
|
||||
|
||||
default:
|
||||
print("Unsupported test-name: " + testName);
|
||||
}
|
||||
@ -83,6 +104,7 @@ public class WorkFlowTestCommand extends AbstractShellCommand {
|
||||
|
||||
/**
|
||||
* Workflow invoke test_name.
|
||||
*
|
||||
* @param num the arg1 of workflow to test_name
|
||||
*/
|
||||
private void invokeSampleTest(int num) {
|
||||
@ -94,9 +116,23 @@ public class WorkFlowTestCommand extends AbstractShellCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workflow datatype exception test.
|
||||
*
|
||||
* @param num the number of workflow to test
|
||||
*/
|
||||
private void invokeExceptionTest(int num) {
|
||||
for (int i = 0; i <= num; i++) {
|
||||
String wpName = "test-" + i;
|
||||
invoke("sample.workflow-3", wpName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invokes workflow.
|
||||
* @param workflowId workflow id
|
||||
*
|
||||
* @param workflowId workflow id
|
||||
* @param workplaceName workplace name
|
||||
*/
|
||||
private void invoke(String workflowId, String workplaceName) {
|
||||
|
||||
@ -15,22 +15,27 @@
|
||||
*/
|
||||
package org.onosproject.workflow.impl;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeType;
|
||||
import org.onosproject.net.config.NetworkConfigRegistry;
|
||||
import org.onosproject.net.config.NetworkConfigService;
|
||||
import org.onosproject.workflow.api.DefaultWorkplace;
|
||||
import org.onosproject.workflow.api.JsonDataModelTree;
|
||||
import org.onosproject.workflow.api.Workflow;
|
||||
import org.onosproject.workflow.api.WorkflowContext;
|
||||
import org.onosproject.workflow.api.WorkflowDescription;
|
||||
import org.onosproject.workflow.api.WorkflowException;
|
||||
import org.onosproject.workflow.api.WorkflowService;
|
||||
import org.onosproject.workflow.api.WorkflowExecutionService;
|
||||
import org.onosproject.workflow.api.WorkflowStore;
|
||||
import org.onosproject.workflow.api.Workplace;
|
||||
import org.onosproject.workflow.api.WorkplaceDescription;
|
||||
import org.onosproject.workflow.api.WorkplaceStore;
|
||||
import org.onosproject.workflow.api.WorkflowStore;
|
||||
import org.onosproject.workflow.api.WorkplaceDescription;
|
||||
import org.onosproject.workflow.api.WorkflowException;
|
||||
import org.onosproject.workflow.api.DefaultWorkplace;
|
||||
import org.onosproject.workflow.api.JsonDataModelTree;
|
||||
import org.onosproject.workflow.api.WorkflowDescription;
|
||||
import org.onosproject.workflow.api.Workplace;
|
||||
import org.onosproject.workflow.api.WorkflowDataModelException;
|
||||
import org.onosproject.workflow.api.Workflow;
|
||||
import org.onosproject.workflow.api.Worklet;
|
||||
import org.onosproject.workflow.api.WorkflowContext;
|
||||
import org.onosproject.workflow.api.JsonDataModel;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
@ -38,8 +43,15 @@ import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
@ -118,21 +130,121 @@ public class WorkflowManager implements WorkflowService {
|
||||
@Override
|
||||
public void invokeWorkflow(JsonNode worklowDescJson) throws WorkflowException {
|
||||
log.info("invokeWorkflow: {}", worklowDescJson);
|
||||
|
||||
Workplace workplace = workplaceStore.getWorkplace(Workplace.SYSTEM_WORKPLACE);
|
||||
if (Objects.isNull(workplace)) {
|
||||
throw new WorkflowException("Invalid system workplace");
|
||||
}
|
||||
|
||||
Workflow workflow = workflowStore.get(URI.create(WorkplaceWorkflow.WF_CREATE_WORKFLOW));
|
||||
Workflow workflow = workflowStore.get(URI.create(worklowDescJson.get("id").asText()));
|
||||
if (Objects.isNull(workflow)) {
|
||||
throw new WorkflowException("Invalid Workflow");
|
||||
}
|
||||
|
||||
if (!checkWorkflowSchema(workflow, worklowDescJson)) {
|
||||
throw new WorkflowException("Invalid Workflow " + worklowDescJson.get("id").asText());
|
||||
}
|
||||
|
||||
Workflow wfCreationWf = workflowStore.get(URI.create(WorkplaceWorkflow.WF_CREATE_WORKFLOW));
|
||||
if (Objects.isNull(wfCreationWf)) {
|
||||
throw new WorkflowException("Invalid workflow " + WorkplaceWorkflow.WF_CREATE_WORKFLOW);
|
||||
}
|
||||
|
||||
WorkflowContext context = workflow.buildSystemContext(workplace, new JsonDataModelTree(worklowDescJson));
|
||||
WorkflowContext context = wfCreationWf.buildSystemContext(workplace, new JsonDataModelTree(worklowDescJson));
|
||||
workflowExecutionService.execInitWorklet(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the type of worklet is same as that of wfdesc Json.
|
||||
*
|
||||
* @param workflow workflow
|
||||
* @param jsonNode jsonNode
|
||||
* @throws WorkflowException workflow exception
|
||||
*/
|
||||
|
||||
private boolean checkWorkflowSchema(Workflow workflow, JsonNode jsonNode) throws WorkflowException {
|
||||
|
||||
Map<String, Map<String, String>> workletDataTypeMap = new HashMap<>();
|
||||
for (String workletType : workflow.getWorkletTypeList()) {
|
||||
Map<String, String> jsonDataModelMap = new HashMap<>();
|
||||
if (Objects.equals(workletType, Worklet.Common.INIT.tag())
|
||||
|| (Objects.equals(workletType, Worklet.Common.COMPLETED.tag()))) {
|
||||
continue;
|
||||
}
|
||||
Worklet worklet = workflow.getWorkletInstance(workletType);
|
||||
Class cls = worklet.getClass();
|
||||
for (Field field : cls.getDeclaredFields()) {
|
||||
if (field.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
Annotation[] annotations = field.getAnnotations();
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation instanceof JsonDataModel) {
|
||||
JsonDataModel jsonDataModel = (JsonDataModel) annotation;
|
||||
Matcher matcher = Pattern.compile("(\\w+)").matcher(jsonDataModel.path());
|
||||
if (!matcher.find()) {
|
||||
throw new WorkflowException("Invalid Json Data Model Path");
|
||||
}
|
||||
String path = matcher.group(1);
|
||||
if (checkJsonNodeDataType(jsonNode, field, path)) {
|
||||
jsonDataModelMap.put(path, field.getType().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!jsonDataModelMap.isEmpty()) {
|
||||
workletDataTypeMap.put(worklet.tag(), jsonDataModelMap);
|
||||
}
|
||||
|
||||
}
|
||||
if (!workletDataTypeMap.isEmpty()) {
|
||||
throw new WorkflowDataModelException("invalid workflow ", workflow.id().toString(), workletDataTypeMap);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean checkJsonNodeDataType(JsonNode jsonNode, Field field, String path) throws WorkflowException {
|
||||
if (!Objects.nonNull(jsonNode.get("data")) && !Objects.nonNull(jsonNode.get("data").get(path))) {
|
||||
throw new WorkflowException("Invalid Json");
|
||||
}
|
||||
JsonNodeType jsonNodeType = jsonNode.get("data").get(path).getNodeType();
|
||||
if (jsonNodeType != null) {
|
||||
switch (jsonNodeType) {
|
||||
case NUMBER:
|
||||
if (!(field.getType().isAssignableFrom(Integer.class))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
if (!(field.getType().isAssignableFrom(String.class))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case OBJECT:
|
||||
if (!(field.getType().isAssignableFrom(Objects.class))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case BOOLEAN:
|
||||
if (!(field.getType().isAssignableFrom(Boolean.class))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ARRAY:
|
||||
if (!(field.getType().isAssignableFrom(Arrays.class))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminateWorkflow(WorkflowDescription wfDesc) throws WorkflowException {
|
||||
log.info("terminateWorkflow: {}", wfDesc);
|
||||
|
||||
@ -116,6 +116,15 @@ public class SampleWorkflow {
|
||||
.chain(SampleWorklet5.class.getName())
|
||||
.build();
|
||||
workflowStore.register(workflow);
|
||||
|
||||
// registering new workflow definition
|
||||
uri = URI.create("sample.workflow-3");
|
||||
workflow = ImmutableListWorkflow.builder()
|
||||
.id(uri)
|
||||
.chain(SampleWorklet6.class.getName())
|
||||
.build();
|
||||
workflowStore.register(workflow);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -308,4 +317,29 @@ public class SampleWorkflow {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for sample worklet-6 to test workflow datamodel exception.
|
||||
*/
|
||||
public static class SampleWorklet6 extends AbsSampleWorklet {
|
||||
|
||||
@JsonDataModel(path = MODEL_COUNT)
|
||||
String str;
|
||||
|
||||
@Override
|
||||
public void process(WorkflowContext context) throws WorkflowException {
|
||||
ObjectNode node = getDataModel(context);
|
||||
node.put("work6", "done");
|
||||
log.info("workflow-process {}-{}", context.workplaceName(), this.getClass().getSimpleName());
|
||||
sleep(10);
|
||||
context.completed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNext(WorkflowContext context) throws WorkflowException {
|
||||
ObjectNode node = allocOrGetModel(context);
|
||||
log.info("workflow-isNext {}-{}", context.workplaceName(), this.getClass().getSimpleName());
|
||||
sleep(10);
|
||||
return !node.has("work6");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user