[ONOS-7732] Automating switch workflow
Change-Id: Ie047c34df2278bc2220cade744f51ca6950f48f6
diff --git a/apps/workflow/api/BUCK b/apps/workflow/api/BUCK
new file mode 100644
index 0000000..c858089
--- /dev/null
+++ b/apps/workflow/api/BUCK
@@ -0,0 +1,11 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//lib:jackson-core',
+ '//lib:jackson-annotations',
+ '//lib:jackson-databind',
+ '//core/store/serializers:onos-core-serializers',
+]
+
+osgi_jar_with_tests(
+ deps = COMPILE_DEPS,
+)
diff --git a/apps/workflow/api/BUILD b/apps/workflow/api/BUILD
new file mode 100644
index 0000000..721e4b9
--- /dev/null
+++ b/apps/workflow/api/BUILD
@@ -0,0 +1,7 @@
+COMPILE_DEPS = CORE_DEPS + KRYO + JACKSON + [
+ "//core/store/serializers:onos-core-serializers",
+]
+
+osgi_jar_with_tests(
+ deps = COMPILE_DEPS,
+)
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/AbstractWorkflow.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/AbstractWorkflow.java
new file mode 100644
index 0000000..5fb8943
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/AbstractWorkflow.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018-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.net.URI;
+
+/**
+ * Abstract class for workflow.
+ */
+public abstract class AbstractWorkflow implements Workflow {
+
+ /**
+ * ID of workflow.
+ */
+ private URI id;
+
+ /**
+ * Constructor for AbstractWorkflow.
+ * @param id ID of workflow
+ */
+ protected AbstractWorkflow(URI id) {
+ this.id = id;
+ }
+
+ @Override
+ public URI id() {
+ return id;
+ }
+
+ @Override
+ public WorkflowContext buildContext(Workplace workplace, DataModelTree data) throws WorkflowException {
+ return DefaultWorkflowContext.builder()
+ .workflowId(id)
+ .workplaceName(workplace.name())
+ .data(data)
+ .build();
+ }
+
+ @Override
+ public WorkflowContext buildSystemContext(Workplace workplace, DataModelTree data) throws WorkflowException {
+ return SystemWorkflowContext.systemBuilder()
+ .workflowId(id)
+ .workplaceName(workplace.name())
+ .data(data)
+ .build();
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/AbstractWorklet.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/AbstractWorklet.java
new file mode 100644
index 0000000..b9fb133
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/AbstractWorklet.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018-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 org.onosproject.event.Event;
+
+/**
+ * Abstract class for worklet.
+ */
+public abstract class AbstractWorklet implements Worklet {
+
+ @Override
+ public String tag() {
+ return this.getClass().getName();
+ }
+
+ @Override
+ public boolean isCompleted(WorkflowContext context, Event event)throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isCompleted should not be called");
+ }
+
+ @Override
+ public boolean isNext(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isNext should not be called");
+ }
+
+ @Override
+ public void timeout(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("Timeout happened");
+ }
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/BranchWorklet.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/BranchWorklet.java
new file mode 100644
index 0000000..4f91bba
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/BranchWorklet.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018-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;
+
+/**
+ * An interface representing branch worklet. Branch worklet is used for branching workflow execution.
+ */
+public interface BranchWorklet extends Worklet {
+
+ @Override
+ default void process(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("This workletType.process should not be called");
+ }
+
+ @Override
+ default boolean isNext(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("This workletType.isNext should not be called");
+ }
+
+ /**
+ * Returns next worklet class for branching.
+ * @param context workflow context
+ * @return next worklet class
+ * @throws WorkflowException workflow exception
+ */
+ Class<? extends Worklet> next(WorkflowContext context) throws WorkflowException;
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/CheckCondition.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/CheckCondition.java
new file mode 100644
index 0000000..7419583
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/CheckCondition.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018-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;
+
+
+/**
+ * Static convenience class that help a whether it was invoked correctly(whether its preconditions have been met).
+ * Methods of this class generally accept a boolean expression which is expected to be true.
+ * When false (or null) is passed instead, the Preconditions method throws an workflow exception.
+ */
+public final class CheckCondition {
+
+ /**
+ * Private class of check condition.
+ */
+ private CheckCondition() {
+ }
+
+ /**
+ * Checks the condition, and if it is false, it raises workflow exception with exception message.
+ * @param condition condition to check. A boolean expression is located on here.
+ * @param exceptionMessage exception message for workflow exception
+ * @throws WorkflowException workflow exception
+ */
+ public static void check(boolean condition, String exceptionMessage) throws WorkflowException {
+ if (!condition) {
+ throw new WorkflowException(exceptionMessage);
+ }
+ }
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ContextEventMapStore.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ContextEventMapStore.java
new file mode 100644
index 0000000..4b54cf3
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ContextEventMapStore.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.store.service.DocumentPath;
+import org.onosproject.store.service.Versioned;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * WorkflowContext Event Map Store.
+ */
+public interface ContextEventMapStore {
+
+ /**
+ * Registers workflow context event mapping.
+ * @param eventType the class name of event
+ * @param eventHintSet Set of event hint string value of the event
+ * @param contextName workflow context name
+ * @param programCounterString the program counter of workflow
+ * @throws WorkflowException workflow exception
+ */
+ void registerEventMap(String eventType, Set<String> eventHintSet,
+ String contextName, String programCounterString) throws WorkflowException;
+
+ /**
+ * Unregisters workflow context event mapping.
+ * @param eventType the class name of event
+ * @param contextName workflow context name
+ * @throws WorkflowException workflow exception
+ */
+ void unregisterEventMap(String eventType,
+ String contextName) throws WorkflowException;
+
+ /**
+ * Returns workflow context event mapping.
+ * @param eventType the class name of event
+ * @param eventHint vent hint string value of the event
+ * @return Map of workflow context and value (program counter)
+ * @throws WorkflowException workflow exception
+ */
+ Map<String, String> getEventMapByHint(String eventType,
+ String eventHint) throws WorkflowException;
+
+ /**
+ * Returns true or false depending on existence of eventMap of given context.
+ * @param contextName name of workflow context
+ * @return Boolean true or false depending on existence of eventMap of given context
+ */
+ boolean isEventMapPresent(String contextName);
+
+ /**
+ * Returns child nodes on document tree path.
+ * @param path document tree path including eventType and Hint
+ * @return children under document tree path
+ * @throws WorkflowException workflow exception
+ */
+ Map<String, Versioned<String>> getChildren(String path) throws WorkflowException;
+
+ /**
+ * Returns document path.
+ * @param path document path string
+ * @return document tree
+ * @throws WorkflowException workflow exception
+ */
+ DocumentPath getDocumentPath(String path) throws WorkflowException;
+
+ /**
+ * Transforms document tree to json tree.
+ * @return json tree
+ * @throws WorkflowException workflow exception
+ */
+ ObjectNode asJsonTree() throws WorkflowException;
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DataModelPointer.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DataModelPointer.java
new file mode 100644
index 0000000..271ce4f
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DataModelPointer.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018-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;
+
+/**
+ * Common data model tree path.
+ */
+public interface DataModelPointer {
+
+ /**
+ * Workplace array pointer.
+ */
+ String WORKPLACES_PTR = "/workplaces";
+
+ /**
+ * Workplace name pointer.
+ */
+ String WORKPLACE_NAME_PTR = "/name";
+
+ /**
+ * Workplace data pointer.
+ */
+ String WORKPLACE_DATA_PTR = "/data";
+
+ /**
+ * Workplace workflow pointer.
+ */
+ String WORKPLACE_WORKFLOWS_PTR = "/workflows";
+
+ /**
+ * Workflow op pointer.
+ */
+ String WORKFLOW_OP_PTR = "/op";
+
+ /**
+ * Workflow id pointer.
+ */
+ String WORKFLOW_ID_PTR = "/id";
+
+ /**
+ * Workflow data pointer.
+ */
+ String WORKFLOW_DATA_PTR = "/data";
+
+ /**
+ * Gets path string.
+ * @return path string
+ */
+ String getPath();
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DataModelTree.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DataModelTree.java
new file mode 100644
index 0000000..f7ada8d
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DataModelTree.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018-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;
+
+/**
+ * Interface for data model tree.
+ */
+public interface DataModelTree {
+
+ /**
+ * Data model tree node type (map or array).
+ */
+ enum Nodetype {
+
+ /**
+ * Map type data model tree node.
+ */
+ MAP,
+
+ /**
+ * Array type data model tree node.
+ */
+ ARRAY
+ }
+
+ /**
+ * Returns subtree on the path.
+ * @param path data model tree path
+ * @return subtree on the path
+ */
+ DataModelTree subtree(String path);
+
+ /**
+ * Attaches subtree on the path.
+ * @param path data model tree path where subtree will be attached
+ * @param tree subtree to be attached
+ * @throws WorkflowException workflow exception
+ */
+ void attach(String path, DataModelTree tree) throws WorkflowException;
+
+ /**
+ * Allocates leaf node on the path.
+ * @param path data model tree path where new leaf node will be allocated
+ * @param leaftype leaf node type
+ * @return data model tree
+ * @throws WorkflowException workflow exception
+ */
+ DataModelTree alloc(String path, Nodetype leaftype) throws WorkflowException;
+
+ /**
+ * Remove node on the path.
+ * @param path data model tree path
+ * @throws WorkflowException workflow exception
+ */
+ void remove(String path) throws WorkflowException;
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultRpcDescription.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultRpcDescription.java
new file mode 100644
index 0000000..6f9d3c3
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultRpcDescription.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.MissingNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import com.google.common.base.MoreObjects;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+/**
+ * Class of workflow RPC description.
+ */
+public final class DefaultRpcDescription implements RpcDescription {
+
+ /**
+ * Workflow RPC operation.
+ */
+ private final String op;
+
+ /**
+ * Parameters.
+ */
+ private final JsonNode params;
+
+ /**
+ * Invocation ID.
+ */
+ private final String id;
+
+ /**
+ * Constructor of workplace description.
+ * @param builder workplace builder
+ */
+ private DefaultRpcDescription(Builder builder) {
+ this.op = builder.op;
+ this.params = builder.params;
+ this.id = builder.id;
+ }
+
+ @Override
+ public String op() {
+ return this.op;
+ }
+
+ @Override
+ public JsonNode params() {
+ return this.params;
+ }
+
+ @Override
+ public String id() {
+ return this.id;
+ }
+
+ /**
+ * Creating workflow RPC description from json tree.
+ * @param root root node for workflow RPC description
+ * @return workflow RPC description
+ * @throws WorkflowException workflow exception
+ */
+ public static DefaultRpcDescription valueOf(JsonNode root) throws WorkflowException {
+
+ JsonNode node = root.at(RPC_OP_PTR);
+ if (!(node instanceof TextNode)) {
+ throw new WorkflowException("invalid RPC operation for " + root);
+ }
+ String rpcOp = node.asText();
+
+ node = root.at(RPC_PARAMS_PTR);
+ if (node instanceof MissingNode) {
+ throw new WorkflowException("invalid RPC parameters for " + root);
+ }
+ JsonNode rpcParams = node;
+
+ node = root.at(RPC_ID_PTR);
+ if (!(node instanceof TextNode)) {
+ throw new WorkflowException("invalid RPC invocation ID for " + root);
+ }
+ String rpcId = node.asText();
+
+
+ return builder()
+ .setOp(rpcOp)
+ .setParams(rpcParams)
+ .setId(rpcId)
+ .build();
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("op", op())
+ .add("params", params())
+ .add("id", id())
+ .toString();
+ }
+
+ /**
+ * Gets builder instance.
+ * @return builder instance
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for workplace RPC description.
+ */
+ public static class Builder {
+
+ /**
+ * Workflow RPC operation.
+ */
+ private String op;
+
+ /**
+ * Parameters.
+ */
+ private JsonNode params;
+
+ /**
+ * Invocation ID.
+ */
+ private String id;
+
+ /**
+ * Sets workflow RPC operation.
+ * @param op workflow RPC operation
+ * @return builder
+ */
+ public Builder setOp(String op) {
+ this.op = op;
+ return this;
+ }
+
+ /**
+ * Sets workflow RPC parameters.
+ * @param params workflow RPC parameters
+ * @return builder
+ */
+ public Builder setParams(JsonNode params) {
+ this.params = params;
+ return this;
+ }
+
+ /**
+ * Sets workflow RPC invocation ID.
+ * @param id workflow invocation ID
+ * @return builder
+ */
+ public Builder setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Builds workplace RPC description from builder.
+ * @return instance of workflow RPC description
+ * @throws WorkflowException workflow exception
+ */
+ public DefaultRpcDescription build() throws WorkflowException {
+ check(op != null, "op is invalid");
+ check(params != null, "params is invalid");
+ check(id != null, "id is invalid");
+ return new DefaultRpcDescription(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkflowContext.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkflowContext.java
new file mode 100644
index 0000000..8f5d3c7
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkflowContext.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceNotFoundException;
+import org.onosproject.event.Event;
+
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+/**
+ * Default implementation of WorkflowContext.
+ */
+public class DefaultWorkflowContext extends WorkflowContext {
+
+ /**
+ * ID of workflow.
+ */
+ private URI workflowId;
+
+ /**
+ * Workplace name of the workflow.
+ */
+ private String workplaceName;
+
+ /**
+ * State of workflow.
+ */
+ private WorkflowState state;
+
+ /**
+ * Current program counter of the workflow.
+ */
+ private ProgramCounter current;
+
+ /**
+ * Cause of workflow exception.
+ */
+ private String cause;
+
+ /**
+ * Completion event type.
+ */
+ private transient Class<? extends Event> completionEventType;
+
+ /**
+ * Completion event hint Set.
+ */
+ private transient Set<String> completionEventHintSet;
+
+ /**
+ * Completion event generator method reference.
+ */
+ private transient WorkExecutor completionEventGenerator;
+
+ /**
+ * Completion event timeout milliseconds.
+ */
+ private transient long completionEventTimeoutMs;
+
+ /**
+ * Service reference for workflow service.
+ */
+ private transient WorkflowExecutionService workflowExecutionService;
+
+ /**
+ * Service reference for workflow store.
+ */
+ private transient WorkflowStore workflowStore;
+
+ /**
+ * Service reference for workplace store.
+ */
+ private transient WorkplaceStore workplaceStore;
+
+ /**
+ * Constructor of DefaultWorkflowContext.
+ * @param builder default workflow context builder
+ */
+ protected DefaultWorkflowContext(Builder builder) {
+ super(builder.data);
+ this.workflowId = builder.workflowId;
+ this.workplaceName = builder.workplaceName;
+ this.state = WorkflowState.IDLE;
+ this.current = ProgramCounter.INIT_PC;
+ }
+
+ /**
+ * DefaultWorkflowContext name builder.
+ * @param workflowid workflow id
+ * @param workplacename workplace name
+ * @return DefaultWorkflowContext name
+ */
+ public static String nameBuilder(URI workflowid, String workplacename) {
+ return workflowid.toString() + "@" + workplacename;
+ }
+
+ @Override
+ public String name() {
+ return nameBuilder(workflowId, workplaceName);
+ }
+
+ @Override
+ public String distributor() {
+ return workplaceName();
+ }
+
+ @Override
+ public URI workflowId() {
+ return this.workflowId;
+ }
+
+ @Override
+ public String workplaceName() {
+ return workplaceName;
+ }
+
+ @Override
+ public WorkflowState state() {
+ return state;
+ }
+
+ @Override
+ public void setState(WorkflowState state) {
+ this.state = state;
+ }
+
+ @Override
+ public ProgramCounter current() {
+ return this.current;
+ }
+
+ @Override
+ public void setCurrent(ProgramCounter pc) {
+ this.current = pc;
+ }
+
+ @Override
+ public String cause() {
+ return this.cause;
+ }
+
+ @Override
+ public void setCause(String cause) {
+ this.cause = cause;
+ }
+
+ @Override
+ public void completed() {
+ setTriggerNext(true);
+ }
+
+ @Override
+ public void waitCompletion(Class<? extends Event> eventType, String eventHint,
+ WorkExecutor eventGenerator, long timeoutMs) {
+ this.completionEventType = eventType;
+ this.completionEventHintSet = new HashSet<>();
+ this.completionEventHintSet.add(eventHint);
+ this.completionEventGenerator = eventGenerator;
+ this.completionEventTimeoutMs = timeoutMs;
+ }
+
+ @Override
+ public void waitAnyCompletion(Class<? extends Event> eventType, Set<String> eventHint,
+ WorkExecutor eventGenerator, long timeoutMs) {
+ this.completionEventType = eventType;
+ this.completionEventHintSet = new HashSet<>();
+ this.completionEventHintSet.addAll(eventHint);
+ this.completionEventGenerator = eventGenerator;
+ this.completionEventTimeoutMs = timeoutMs;
+ }
+
+ @Override
+ public void waitFor(long timeoutMs) {
+ this.completionEventTimeoutMs = timeoutMs;
+ }
+
+ @Override
+ public Class<? extends Event> completionEventType() {
+ return completionEventType;
+ }
+
+ @Override
+ public Set<String> completionEventHints() {
+ return completionEventHintSet;
+ }
+
+ @Override
+ public WorkExecutor completionEventGenerator() {
+ return completionEventGenerator;
+ }
+
+ @Override
+ public long completionEventTimeout() {
+ return completionEventTimeoutMs;
+ }
+
+ @Override
+ public void setWorkflowExecutionService(WorkflowExecutionService workflowExecutionService) {
+ this.workflowExecutionService = workflowExecutionService;
+ }
+
+ @Override
+ public WorkflowExecutionService workflowService() {
+ return workflowExecutionService;
+ }
+
+ @Override
+ public void setWorkflowStore(WorkflowStore workflowStore) {
+ this.workflowStore = workflowStore;
+ }
+
+ @Override
+ public WorkflowStore workflowStore() {
+ return workflowStore;
+ }
+
+ @Override
+ public void setWorkplaceStore(WorkplaceStore workplaceStore) {
+ this.workplaceStore = workplaceStore;
+ }
+
+ @Override
+ public WorkplaceStore workplaceStore() {
+ return workplaceStore;
+ }
+
+ public <T> T getService(Class<T> serviceClass) throws WorkflowException {
+ T service;
+ try {
+ service = DefaultServiceDirectory.getService(serviceClass);
+ } catch (ServiceNotFoundException e) {
+ throw new WorkflowException(e);
+ }
+ return service;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("name", name())
+ .add("triggernext", triggerNext())
+ .add("data", data())
+ .add("current", current)
+ .add("state", state())
+ .add("cause", cause())
+ .toString();
+ }
+
+ /**
+ * Gets builder instance.
+ * @return builder instance
+ */
+ public static final Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for default workflow context.
+ */
+ public static class Builder {
+
+ /**
+ * ID of workflow.
+ */
+ private URI workflowId;
+
+ /**
+ * Workplace name of the workflow.
+ */
+ private String workplaceName;
+
+ /**
+ * Data model tree.
+ */
+ private DataModelTree data;
+
+ /**
+ * Sets workflow id.
+ * @param workflowId workflow id
+ * @return builder
+ */
+ public Builder workflowId(URI workflowId) {
+ this.workflowId = workflowId;
+ return this;
+ }
+
+ /**
+ * Sets workplace name.
+ * @param workplaceName workplace name
+ * @return builder
+ */
+ public Builder workplaceName(String workplaceName) {
+ this.workplaceName = workplaceName;
+ return this;
+ }
+
+ /**
+ * Sets data model tree.
+ * @param data data model tree
+ * @return builder
+ */
+ public Builder data(DataModelTree data) {
+ this.data = data;
+ return this;
+ }
+
+ /**
+ * Builds default workflow context.
+ * @return instance of default workflow context
+ * @throws WorkflowException workflow exception
+ */
+ public DefaultWorkflowContext build() throws WorkflowException {
+ check(data != null, "Invalid data model tree");
+ check(workflowId != null, "Invalid workflowId");
+ check(workplaceName != null, "Invalid workplaceName");
+ return new DefaultWorkflowContext(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkflowDescription.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkflowDescription.java
new file mode 100644
index 0000000..13a8f46
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkflowDescription.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.MissingNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import com.google.common.base.MoreObjects;
+
+import java.net.URI;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+
+/**
+ * Class for default workflow description.
+ */
+public final class DefaultWorkflowDescription implements WorkflowDescription {
+
+ /**
+ * Workplace Name.
+ */
+ private String workplaceName;
+
+ /**
+ * Workflow ID.
+ */
+ private URI id;
+
+ /**
+ * Workflow data model.
+ */
+ private JsonNode data;
+
+ /**
+ * Constructor of workflow description.
+ * @param builder workflow description builder
+ */
+ private DefaultWorkflowDescription(Builder builder) {
+ this.workplaceName = builder.workplaceName;
+ this.id = builder.id;
+ this.data = builder.data;
+ }
+
+ @Override
+ public String workplaceName() {
+ return this.workplaceName;
+ }
+
+ @Override
+ public URI id() {
+ return this.id;
+ }
+
+ @Override
+ public String workflowContextName() {
+ return DefaultWorkflowContext.nameBuilder(id(), workplaceName());
+ }
+
+ @Override
+ public JsonNode data() {
+ return this.data;
+ }
+
+ /**
+ * Creating workflow description from json tree.
+ * @param root root node for workflow description
+ * @return workflow description
+ * @throws WorkflowException workflow exception
+ */
+ public static DefaultWorkflowDescription valueOf(JsonNode root) throws WorkflowException {
+
+ JsonNode node = root.at(ptr(WF_WORKPLACE));
+ if (!(node instanceof TextNode)) {
+ throw new WorkflowException("invalid workflow workplace for " + root);
+ }
+ String wfWorkplaceName = node.asText();
+
+ node = root.at(ptr(WF_ID));
+ if (!(node instanceof TextNode)) {
+ throw new WorkflowException("invalid workflow id for " + root);
+ }
+ URI wfId = URI.create(node.asText());
+
+ node = root.at(ptr(WF_DATA));
+ if (node instanceof MissingNode) {
+ throw new WorkflowException("invalid workflow data for " + root);
+ }
+ JsonNode wfData = node;
+
+ return builder()
+ .workplaceName(wfWorkplaceName)
+ .id(wfId)
+ .data(wfData)
+ .build();
+ }
+
+ private static String ptr(String field) {
+ return "/" + field;
+ }
+
+ @Override
+ public JsonNode toJson() {
+ ObjectNode root = JsonNodeFactory.instance.objectNode();
+ root.put(WF_WORKPLACE, workplaceName());
+ root.put(WF_ID, id().toString());
+ root.put(WF_DATA, data());
+ return root;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("workplace", workplaceName())
+ .add("id", id())
+ .add("data", data())
+ .toString();
+ }
+
+ /**
+ * Gets builder instance.
+ * @return builder instance
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for workflow description.
+ */
+ public static class Builder {
+
+ /**
+ * Workplace name.
+ */
+ private String workplaceName;
+
+ /**
+ * Workflow ID.
+ */
+ private URI id;
+
+ /**
+ * Workflow data model.
+ */
+ private JsonNode data;
+
+ /**
+ * Sets workplace name.
+ * @param workplaceName workplace name
+ * @return builder
+ */
+ public Builder workplaceName(String workplaceName) {
+ this.workplaceName = workplaceName;
+ return this;
+ }
+
+ /**
+ * Sets workflow id.
+ * @param id workflow ID
+ * @return builder
+ */
+ public Builder id(URI id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Sets workflow id.
+ * @param id workflow ID string
+ * @return builder
+ */
+ public Builder id(String id) {
+ this.id = URI.create(id);
+ return this;
+ }
+
+ /**
+ * Sets workflow data model.
+ * @param data workflow data model
+ * @return builder
+ */
+ public Builder data(JsonNode data) {
+ this.data = data;
+ return this;
+ }
+
+ /**
+ * Builds workflow description from builder.
+ * @return instance of workflow description
+ * @throws WorkflowException workflow exception
+ */
+ public DefaultWorkflowDescription build() throws WorkflowException {
+ check(workplaceName != null, "workplaceName is invalid");
+ check(id != null, "id is invalid");
+ check(data != null, "data is invalid");
+ return new DefaultWorkflowDescription(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkplace.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkplace.java
new file mode 100644
index 0000000..1c60eaf
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkplace.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceNotFoundException;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Collectors;
+
+/**
+ * Default implementation of workplace.
+ */
+public class DefaultWorkplace extends Workplace {
+
+ /**
+ * Name of workplace.
+ */
+ private String name;
+
+ /**
+ * Constructor of DefaultWorkplace.
+ * @param name name of workplace
+ * @param data data model tree
+ */
+ public DefaultWorkplace(String name, DataModelTree data) {
+ super(data);
+ this.name = name;
+ }
+
+ @Override
+ public String name() {
+ return this.name;
+ }
+
+ @Override
+ public String distributor() {
+ return name();
+ }
+
+ @Override
+ public Collection<WorkflowContext> getContexts() throws WorkflowException {
+ WorkplaceStore workplaceStore;
+ try {
+ workplaceStore = DefaultServiceDirectory.getService(WorkplaceStore.class);
+ } catch (ServiceNotFoundException e) {
+ throw new WorkflowException(e);
+ }
+
+ return workplaceStore.getWorkplaceContexts(name());
+ }
+
+ /**
+ * Returns collection of context names.
+ * @return collection of context names
+ */
+ private Collection<String> getContextNames() {
+ Collection<WorkflowContext> ctx;
+ try {
+ ctx = getContexts();
+ } catch (WorkflowException e) {
+ ctx = Collections.emptyList();
+ }
+
+ return ctx.stream().map(x -> x.name()).collect(Collectors.toList());
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("name", name())
+ .add("triggernext", triggerNext())
+ .add("context", data())
+ .add("contexts", getContextNames())
+ .toString();
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkplaceDescription.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkplaceDescription.java
new file mode 100644
index 0000000..e8125f7
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/DefaultWorkplaceDescription.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.MissingNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import com.google.common.base.MoreObjects;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+/**
+ * Class for default workplace description.
+ */
+public final class DefaultWorkplaceDescription implements WorkplaceDescription {
+
+ /**
+ * Name of workplace.
+ */
+ private final String name;
+
+ /**
+ * Data model of workplace(Optional).
+ */
+ private final Optional<JsonNode> optData;
+
+ /**
+ * Constructor of workplace description.
+ * @param builder workplace builder
+ */
+ private DefaultWorkplaceDescription(Builder builder) {
+ this.name = builder.name;
+ this.optData = builder.optData;
+ }
+
+ @Override
+ public String name() {
+ return this.name;
+ }
+
+ @Override
+ public Optional<JsonNode> data() {
+ return this.optData;
+ }
+
+ /**
+ * Creating workplace description from json tree.
+ * @param root root node for workplace description
+ * @return workplace description
+ * @throws WorkflowException workflow exception
+ */
+ public static DefaultWorkplaceDescription valueOf(JsonNode root) throws WorkflowException {
+
+ JsonNode node = root.at(ptr(WP_NAME));
+ if (!(node instanceof TextNode)) {
+ throw new WorkflowException("invalid workplace name for " + root);
+ }
+
+ Builder builder = builder()
+ .name(node.asText());
+
+ node = root.at(ptr(WP_DATA));
+ if (node != null && !(node instanceof MissingNode)) {
+ if (!(node instanceof ObjectNode) && !(node instanceof ArrayNode)) {
+ throw new WorkflowException("invalid workplace data for " + root);
+ }
+ builder.data(node);
+ }
+
+ return builder.build();
+ }
+
+ private static String ptr(String field) {
+ return "/" + field;
+ }
+
+ @Override
+ public JsonNode toJson() {
+ ObjectNode root = JsonNodeFactory.instance.objectNode();
+ root.put(WP_NAME, name());
+ if (data().isPresent()) {
+ root.put(WP_DATA, data().get());
+ }
+ return root;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("name", name())
+ .add("optData", data())
+ .toString();
+ }
+
+ /**
+ * Gets builder instance.
+ * @return builder instance
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for workplace description.
+ */
+ public static class Builder {
+
+ /**
+ * Workplace name.
+ */
+ private String name;
+
+ /**
+ * Workplace optData model.
+ */
+ private Optional<JsonNode> optData = Optional.empty();
+
+ /**
+ * List of workflow.
+ */
+ private List<DefaultWorkflowDescription> workflowDescs = new ArrayList<DefaultWorkflowDescription>();
+
+ /**
+ * Sets workplace name.
+ * @param name workplace name
+ * @return builder
+ */
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Sets optData model.
+ * @param data workplace optData model
+ * @return builder
+ */
+ public Builder data(JsonNode data) {
+ this.optData = Optional.of(data);
+ return this;
+ }
+
+ /**
+ * Builds workplace description from builder.
+ * @return instance of workflow description
+ * @throws WorkflowException workflow exception
+ */
+ public DefaultWorkplaceDescription build() throws WorkflowException {
+ check(name != null, "name is invalid");
+ return new DefaultWorkplaceDescription(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventHintSupplier.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventHintSupplier.java
new file mode 100644
index 0000000..076bfc0
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventHintSupplier.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018-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 org.onosproject.event.Event;
+
+/**
+ * Functional interface for delivering event hint supplier.
+ */
+@FunctionalInterface
+public interface EventHintSupplier {
+ String apply(Event event) throws Throwable;
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventTask.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventTask.java
new file mode 100644
index 0000000..c2af3e6
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventTask.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+import org.onosproject.event.Event;
+
+import java.util.Objects;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+/**
+ * Class for event task.
+ */
+public final class EventTask extends HandlerTask {
+
+ /**
+ * Event triggering event task.
+ */
+ private final Event event;
+
+ /**
+ * Event hint value for finding target event.
+ */
+ private final String eventHint;
+
+ /**
+ * Constructor of event task.
+ * @param builder builder of event task
+ */
+ private EventTask(Builder builder) {
+ super(builder);
+ this.event = builder.event;
+ this.eventHint = builder.eventHint;
+ }
+
+ /**
+ * Gets event of event task.
+ * @return event triggering event task
+ */
+ public Event event() {
+ return event;
+ }
+
+ /**
+ * Gets event type (class name of event) of event task.
+ * @return event type
+ */
+ public String eventType() {
+ return event.getClass().getName();
+ }
+
+ /**
+ * Gets event hint of event task.
+ * @return event hint string
+ */
+ public String eventHint() {
+ return eventHint;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.toString());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof EventTask)) {
+ return false;
+ }
+ return Objects.equals(this.event(), ((EventTask) obj).event())
+ && Objects.equals(this.eventType(), ((EventTask) obj).eventType())
+ && Objects.equals(this.eventHint(), ((EventTask) obj).eventHint());
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("context", context())
+ .add("programCounter", programCounter())
+ .add("event", event())
+ .add("eventHint", eventHint())
+ .toString();
+ }
+
+ /**
+ * Gets a instance of builder.
+ * @return instance of builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of EventTask.
+ */
+ public static class Builder extends HandlerTask.Builder {
+
+ /**
+ * Event triggering event task.
+ */
+ private Event event;
+
+ /**
+ * Event hint value for finding target event.
+ */
+ private String eventHint;
+
+ /**
+ * Sets event.
+ * @param event event triggering event task
+ * @return Builder of EventTask
+ */
+ public Builder event(Event event) {
+ this.event = event;
+ return this;
+ }
+
+ /**
+ * Sets event hint.
+ * @param eventHint event hint value for finding target event
+ * @return Builder of EventTask
+ */
+ public Builder eventHint(String eventHint) {
+ this.eventHint = eventHint;
+ return this;
+ }
+
+ @Override
+ public Builder context(WorkflowContext context) {
+ super.context(context);
+ return this;
+ }
+
+ @Override
+ public Builder programCounter(ProgramCounter programCounter) {
+ super.programCounter(programCounter);
+ return this;
+ }
+
+ /**
+ * Builds EventTask.
+ * @return instance of EventTask
+ * @throws WorkflowException workflow exception
+ */
+ public EventTask build() throws WorkflowException {
+ check(event != null, "event is invalid");
+ check(eventHint != null, "eventHint is invalid");
+ return new EventTask(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventTimeoutTask.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventTimeoutTask.java
new file mode 100644
index 0000000..2ee2672
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/EventTimeoutTask.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+/**
+ * Class for event timeout task.
+ */
+public final class EventTimeoutTask extends HandlerTask {
+
+ /**
+ * Event type (Class name of event).
+ */
+ private final String eventType;
+
+ /**
+ * Set of Event hint value for finding target event.
+ */
+ private final Set<String> eventHintSet = new HashSet<>();
+
+ /**
+ * Constructor of EventTimeoutTask.
+ * @param builder builder of EventTimeoutTask
+ */
+ private EventTimeoutTask(Builder builder) {
+ super(builder);
+ this.eventType = builder.eventType;
+ this.eventHintSet.addAll(builder.eventHintSet);
+ }
+
+ /**
+ * Gets event type (Class name of event).
+ * @return event type
+ */
+ public String eventType() {
+ return eventType;
+ }
+
+ /**
+ * Gets set of event hint value for finding target event.
+ * @return event hint set
+ */
+ public Set<String> eventHintSet() {
+ return eventHintSet;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.toString());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof EventTask)) {
+ return false;
+ }
+ return Objects.equals(this.eventType(), ((EventTask) obj).eventType())
+ && Objects.equals(this.eventHintSet(), ((EventTask) obj).eventHint());
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("context", context())
+ .add("programCounter", programCounter())
+ .add("eventType", eventType())
+ .add("eventHint", eventHintSet())
+ .toString();
+ }
+
+ /**
+ * Gets a instance of builder.
+ * @return instance of builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of EventTimeoutTask.
+ */
+ public static class Builder extends HandlerTask.Builder {
+ /**
+ * Event type (Class name of event).
+ */
+ private String eventType;
+
+ /**
+ * Set of Event hint value for finding target event.
+ */
+ private Set<String> eventHintSet;
+
+ /**
+ * Sets Event type (Class name of event).
+ * @param eventType event type
+ * @return builder of EventTimeoutTask
+ */
+ public Builder eventType(String eventType) {
+ this.eventType = eventType;
+ return this;
+ }
+
+ /**
+ * Sets event hint string for finding target event.
+ * @param eventHintSet Set of event hint string
+ * @return builder of EventTimeoutTask
+ */
+ public Builder eventHintSet(Set<String> eventHintSet) {
+ this.eventHintSet = eventHintSet;
+ return this;
+ }
+
+ @Override
+ public Builder context(WorkflowContext context) {
+ super.context(context);
+ return this;
+ }
+
+ @Override
+ public Builder programCounter(ProgramCounter programCounter) {
+ super.programCounter(programCounter);
+ return this;
+ }
+
+ /**
+ * Builds EventTimeoutTask.
+ * @return instance of EventTimeoutTask
+ * @throws WorkflowException workflow exception
+ */
+ public EventTimeoutTask build() throws WorkflowException {
+ check(eventType != null, "eventType is invalid");
+ check(eventHintSet != null, "eventHintSet is invalid");
+ return new EventTimeoutTask(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/HandlerTask.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/HandlerTask.java
new file mode 100644
index 0000000..94203bc
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/HandlerTask.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+
+/**
+ * Abstract class for handler task.
+ */
+public abstract class HandlerTask {
+
+ /**
+ * Workflow context of handler task.
+ */
+ private final WorkflowContext context;
+
+ /**
+ * Program counter of handler task.
+ */
+ private final ProgramCounter programCounter;
+
+ /**
+ * Constructor for handler task.
+ * @param builder handler task builder
+ */
+ protected HandlerTask(Builder builder) {
+ this.context = builder.context;
+ this.programCounter = builder.programCounter;
+ }
+
+ /**
+ * Returns workflow context of this handler task.
+ * @return workflow context
+ */
+ public WorkflowContext context() {
+ return context;
+ }
+
+ /**
+ * Returns program counter of this handler task.
+ * @return program counter
+ */
+ public ProgramCounter programCounter() {
+ return programCounter;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("context", context())
+ .add("programCounter", programCounter())
+ .toString();
+ }
+
+ /**
+ * Builder of HandlerTask.
+ */
+ public static class Builder {
+ protected WorkflowContext context;
+ protected ProgramCounter programCounter;
+
+ /**
+ * Sets workflow context of handler task.
+ * @param context workflow context
+ * @return builder of handler task
+ */
+ public Builder context(WorkflowContext context) {
+ this.context = context;
+ return this;
+ }
+
+ /**
+ * Sets program counter of handler task.
+ * @param programCounter program counter of handler type
+ * @return builder of handler task
+ */
+ public Builder programCounter(ProgramCounter programCounter) {
+ this.programCounter = programCounter;
+ return this;
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/HandlerTaskBatchDelegate.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/HandlerTaskBatchDelegate.java
new file mode 100644
index 0000000..c5859f2
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/HandlerTaskBatchDelegate.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018-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.Collection;
+
+/**
+ * Facade for receiving notifications from the handler task batch service.
+ */
+public interface HandlerTaskBatchDelegate {
+
+ /**
+ * Submits the specified batch of handler task operations for processing.
+ *
+ * @param operations batch of operations
+ */
+ void execute(Collection<Collection<HandlerTask>> operations);
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ImmutableListWorkflow.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ImmutableListWorkflow.java
new file mode 100644
index 0000000..ec2be65
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ImmutableListWorkflow.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceNotFoundException;
+
+import java.lang.reflect.Modifier;
+import java.net.URI;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+/**
+ * Class for immutable list workflow.
+ */
+public final class ImmutableListWorkflow extends AbstractWorkflow {
+
+ /**
+ * Init worklet type(class name of init worklet type).
+ */
+ private String initWorkletType;
+
+ /**
+ * List of worklet.
+ */
+ private List<String> workletTypeList;
+
+ /**
+ * Set of workflow attributes.
+ */
+ private Set<WorkflowAttribute> attributes;
+
+ private static JsonDataModelInjector dataModelInjector = new JsonDataModelInjector();
+
+ /**
+ * Constructor of ImmutableListWorkflow.
+ *
+ * @param builder builder of ImmutableListWorkflow
+ */
+ private ImmutableListWorkflow(Builder builder) {
+ super(builder.id);
+ this.initWorkletType = builder.initWorkletType;
+ workletTypeList = ImmutableList.copyOf(builder.workletTypeList);
+ attributes = ImmutableSet.copyOf(builder.attributes);
+ }
+
+ @Override
+ public Worklet init(WorkflowContext context) throws WorkflowException {
+ if (Objects.isNull(initWorkletType)) {
+ return null;
+ }
+
+ return getWorkletInstance(initWorkletType);
+ }
+
+
+ @Override
+ public ProgramCounter next(WorkflowContext context) throws WorkflowException {
+
+ int cnt = 0;
+
+ ProgramCounter pc = context.current();
+ check(pc != null, "Invalid program counter");
+
+ for (int i = pc.workletIndex(); i < workletTypeList.size(); i++) {
+
+ if (cnt++ > Worklet.MAX_WORKS) {
+ throw new WorkflowException("Maximum worklet execution exceeded");
+ }
+
+ String workletType = workletTypeList.get(i);
+
+ if (Worklet.Common.COMPLETED.tag().equals(workletType)) {
+ return ProgramCounter.valueOf(workletType, i);
+ }
+
+ if (Worklet.Common.INIT.tag().equals(workletType)) {
+ continue;
+ }
+
+ Worklet worklet = getWorkletInstance(workletType);
+ Class workClass = worklet.getClass();
+
+ if (BranchWorklet.class.isAssignableFrom(workClass)) {
+ Class nextClass = ((BranchWorklet) worklet).next(context);
+ if (nextClass == null) {
+ throw new WorkflowException("Invalid next Worklet for " + workClass);
+ }
+
+ // TODO : it does not support duplicated use of WorkType. It needs to consider label concept
+ int nextIdx = getClassIndex(nextClass);
+ if (nextIdx == -1) {
+ throw new WorkflowException("Failed to find next " + nextClass + " for " + workClass);
+ }
+
+ i = nextIdx;
+ continue;
+
+ } else {
+ // isNext is read only. It does not perform 'inhale'.
+ dataModelInjector.inject(worklet, context);
+ if (worklet.isNext(context)) {
+ return ProgramCounter.valueOf(workletType, i);
+ }
+ }
+ }
+ throw new WorkflowException("workflow reached to end but not COMPLETED");
+ }
+
+ @Override
+ public ProgramCounter increased(ProgramCounter pc) throws WorkflowException {
+
+ int increaedIndex = pc.workletIndex() + 1;
+ if (increaedIndex >= workletTypeList.size()) {
+ throw new WorkflowException("Out of bound in program counter(" + pc + ")");
+ }
+
+ String workletType = workletTypeList.get(increaedIndex);
+ return ProgramCounter.valueOf(workletType, increaedIndex);
+ }
+
+ @Override
+ public Worklet getWorkletInstance(String workletType) throws WorkflowException {
+
+ if (Worklet.Common.INIT.tag().equals(workletType)) {
+ return Worklet.Common.INIT;
+ }
+
+ if (Worklet.Common.COMPLETED.tag().equals(workletType)) {
+ return Worklet.Common.COMPLETED;
+ }
+
+ WorkflowStore store;
+ try {
+ store = DefaultServiceDirectory.getService(WorkflowStore.class);
+ } catch (ServiceNotFoundException e) {
+ throw new WorkflowException(e);
+ }
+
+ Class workClass;
+ try {
+ workClass = store.getClass(workletType);
+ } catch (ClassNotFoundException e) {
+ throw new WorkflowException(e);
+ }
+
+ if (!isAllowed(workClass)) {
+ throw new WorkflowException("Not allowed class(" + workClass.getSimpleName() + ")");
+ }
+
+ Worklet worklet;
+ try {
+ worklet = (Worklet) workClass.newInstance();
+ } catch (Exception e) {
+ throw new WorkflowException(e);
+ }
+
+ return worklet;
+ }
+
+ @Override
+ public Set<WorkflowAttribute> attributes() {
+ 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
+ */
+ private int getClassIndex(Class aClass) {
+ for (int i = 0; i < workletTypeList.size(); i++) {
+ if (Objects.equals(aClass.getName(), workletTypeList.get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks whether class is allowed class or not.
+ *
+ * @param clazz class to check
+ * @return Check result
+ */
+ private boolean isAllowed(Class clazz) {
+ // non static inner class is not allowed
+ if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
+ return false;
+ }
+ // enum is not allowed
+ if (clazz.isEnum()) {
+ return false;
+ }
+ // class should be subclass of Work
+ if (!Worklet.class.isAssignableFrom(clazz)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.toString());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof EventTask)) {
+ return false;
+ }
+ return Objects.equals(this.id(), ((ImmutableListWorkflow) obj).id())
+ && Objects.equals(this.initWorkletType, ((ImmutableListWorkflow) obj).initWorkletType)
+ && Objects.equals(this.workletTypeList, ((ImmutableListWorkflow) obj).workletTypeList)
+ && Objects.equals(this.attributes, ((ImmutableListWorkflow) obj).attributes);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("id", id())
+ .add("initWorklet", initWorkletType)
+ .add("workList", workletTypeList)
+ .add("attributes", attributes)
+ .toString();
+ }
+
+ /**
+ * Gets a instance of builder.
+ *
+ * @return instance of builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of ImmutableListWorkflow.
+ */
+ public static class Builder {
+
+ private URI id;
+ private String initWorkletType;
+ private final List<String> workletTypeList = Lists.newArrayList();
+ private final Set<WorkflowAttribute> attributes = Sets.newHashSet();
+
+ /**
+ * Sets id of immutable list workflow.
+ *
+ * @param uri id of immutable list workflow
+ * @return builder
+ */
+ public Builder id(URI uri) {
+ this.id = uri;
+ workletTypeList.add(Worklet.Common.INIT.tag());
+ return this;
+ }
+
+ /**
+ * Sets init worklet class name of immutable list workflow.
+ *
+ * @param workletClassName class name of worklet
+ * @return builder
+ */
+ public Builder init(String workletClassName) {
+ this.initWorkletType = workletClassName;
+ return this;
+ }
+
+ /**
+ * Chains worklet class name of immutable list workflow.
+ *
+ * @param workletClassName class name of worklet
+ * @return builder
+ */
+ public Builder chain(String workletClassName) {
+ workletTypeList.add(workletClassName);
+ return this;
+ }
+
+ /**
+ * Adds workflow attribute.
+ *
+ * @param attribute workflow attribute to be added
+ * @return builder
+ */
+ public Builder attribute(WorkflowAttribute attribute) {
+ attributes.add(attribute);
+ return this;
+ }
+
+ /**
+ * Builds ImmutableListWorkflow.
+ *
+ * @return instance of ImmutableListWorkflow
+ */
+ public ImmutableListWorkflow build() {
+ workletTypeList.add(Worklet.Common.COMPLETED.tag());
+ return new ImmutableListWorkflow(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModel.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModel.java
new file mode 100644
index 0000000..fb26642
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018-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.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+
+/**
+ * Annotation for injecting json data model on work-let execution context.
+ */
+public @interface JsonDataModel {
+
+ /**
+ * Path of data model.
+ *
+ * @return path of data model
+ */
+ String path() default "/";
+
+ /**
+ * Representing whether this data model is optional or not.
+ *
+ * @return optional or not
+ */
+ boolean optional() default false;
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModelInjector.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModelInjector.java
new file mode 100644
index 0000000..6f87411
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModelInjector.java
@@ -0,0 +1,605 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.BooleanNode;
+import com.fasterxml.jackson.databind.node.IntNode;
+import com.fasterxml.jackson.databind.node.MissingNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Class for injecting json data model on the work-let execution context.
+ */
+public class JsonDataModelInjector {
+
+ private static final Logger log = LoggerFactory.getLogger(JsonDataModelInjector.class);
+
+ /**
+ * Injects data model to work-let.
+ *
+ * @param worklet work-let to be injected
+ * @param context workflow context
+ * @throws WorkflowException workflow exception
+ */
+ public void inject(Worklet worklet, WorkflowContext context) throws WorkflowException {
+
+ handle(worklet, context, this::injectModel);
+ }
+
+ /**
+ * Inhales data model from work-let.
+ *
+ * @param worklet work-let to be inhaled
+ * @param context workflow context
+ * @throws WorkflowException workflow exception
+ */
+ public void inhale(Worklet worklet, WorkflowContext context) throws WorkflowException {
+
+ handle(worklet, context, this::inhaleModel);
+ }
+
+ private void handle(Worklet worklet, WorkflowContext context, DataModelFieldBehavior func)
+ throws WorkflowException {
+ Class cl = worklet.getClass();
+ List<Field> fields = getInheritedFields(cl);
+ if (Objects.isNull(fields)) {
+ log.error("Invalid fields on {}", cl);
+ return;
+ }
+
+ for (Field field : fields) {
+ Annotation[] annotations = field.getAnnotations();
+ if (Objects.isNull(annotations)) {
+ continue;
+ }
+ for (Annotation annotation : annotations) {
+ if (!(annotation instanceof JsonDataModel)) {
+ continue;
+ }
+ JsonDataModel model = (JsonDataModel) annotation;
+ func.apply(worklet, context, field, model);
+ }
+ }
+ }
+
+ private static List<Field> getInheritedFields(Class<?> type) {
+ List<Field> fields = new ArrayList<Field>();
+
+ Class<?> cl = type;
+ while (cl != null && cl != Object.class) {
+ for (Field field : cl.getDeclaredFields()) {
+ if (!field.isSynthetic()) {
+ fields.add(field);
+ }
+ }
+ cl = cl.getSuperclass();
+ }
+ return fields;
+ }
+
+ /**
+ * Functional interface for json data model annotated field behavior.
+ */
+ @FunctionalInterface
+ public interface DataModelFieldBehavior {
+ void apply(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException;
+ }
+
+ private static Map<Class, DataModelFieldBehavior> injectTypeMap = new HashMap<>();
+
+ static {
+ injectTypeMap.put(String.class, JsonDataModelInjector::injectText);
+ injectTypeMap.put(Integer.class, JsonDataModelInjector::injectInteger);
+ injectTypeMap.put(Boolean.class, JsonDataModelInjector::injectBoolean);
+ injectTypeMap.put(JsonNode.class, JsonDataModelInjector::injectJsonNode);
+ injectTypeMap.put(ArrayNode.class, JsonDataModelInjector::injectArrayNode);
+ injectTypeMap.put(ObjectNode.class, JsonDataModelInjector::injectObjectNode);
+ }
+
+ /**
+ * Injects data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private void injectModel(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ DataModelFieldBehavior behavior = injectTypeMap.get(field.getType());
+ if (Objects.isNull(behavior)) {
+ throw new WorkflowException("Not supported type(" + field.getType() + ")");
+ }
+ behavior.apply(worklet, context, field, model);
+ }
+
+ /**
+ * Injects text data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model text data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void injectText(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ String text = ((JsonDataModelTree) context.data()).textAt(model.path());
+ if (Objects.isNull(text)) {
+ if (model.optional()) {
+ return;
+ }
+ throw new WorkflowException("Invalid text data model on (" + model.path() + ")");
+ }
+
+ if (!(Objects.equals(field.getType(), String.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not String");
+ }
+
+ try {
+ field.setAccessible(true);
+ field.set(worklet, text);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+ }
+
+ /**
+ * Injects integer data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model integer data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void injectInteger(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+ Integer number = ((JsonDataModelTree) context.data()).intAt(model.path());
+ if (Objects.isNull(number)) {
+ if (model.optional()) {
+ return;
+ }
+ throw new WorkflowException("Invalid number data model on (" + model.path() + ")");
+ }
+
+ if (!(Objects.equals(field.getType(), Integer.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not Integer");
+ }
+
+ try {
+ field.setAccessible(true);
+ field.set(worklet, number);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+ }
+
+ /**
+ * Injects boolean data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model boolean data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void injectBoolean(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ Boolean bool = ((JsonDataModelTree) context.data()).booleanAt(model.path());
+ if (Objects.isNull(bool)) {
+ if (model.optional()) {
+ return;
+ }
+ throw new WorkflowException("Invalid boolean data model on (" + model.path() + ")");
+ }
+
+ if (!(Objects.equals(field.getType(), Boolean.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not Boolean");
+ }
+
+ try {
+ field.setAccessible(true);
+ field.set(worklet, bool);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+ }
+
+ /**
+ * Injects json node data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model json node data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void injectJsonNode(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ JsonNode jsonNode = ((JsonDataModelTree) context.data()).nodeAt(model.path());
+ if (Objects.isNull(jsonNode)) {
+ if (model.optional()) {
+ return;
+ }
+ throw new WorkflowException("Invalid json node data model on (" + model.path() + ")");
+ }
+
+ if (!(Objects.equals(field.getType(), JsonNode.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not JsonNode");
+ }
+
+ try {
+ field.setAccessible(true);
+ field.set(worklet, jsonNode);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+ }
+
+ /**
+ * Injects json array node data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model json array node data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void injectArrayNode(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ ArrayNode arrayNode = ((JsonDataModelTree) context.data()).arrayAt(model.path());
+ if (Objects.isNull(arrayNode)) {
+ if (model.optional()) {
+ return;
+ }
+ throw new WorkflowException("Invalid array node data model on (" + model.path() + ")");
+ }
+
+ if (!(Objects.equals(field.getType(), ArrayNode.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not ArrayNode");
+ }
+
+ try {
+ field.setAccessible(true);
+ field.set(worklet, arrayNode);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+ }
+
+ /**
+ * Injects json object node data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model json object node data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void injectObjectNode(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ ObjectNode objNode = ((JsonDataModelTree) context.data()).objectAt(model.path());
+ if (Objects.isNull(objNode)) {
+ if (model.optional()) {
+ return;
+ }
+ throw new WorkflowException("Invalid object node data model on (" + model.path() + ")");
+ }
+
+ if (!(Objects.equals(field.getType(), ObjectNode.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not ObjectNode");
+ }
+
+ try {
+ field.setAccessible(true);
+ field.set(worklet, objNode);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+ }
+
+ private static Map<Class, DataModelFieldBehavior> inhaleTypeMap = new HashMap<>();
+
+ static {
+ inhaleTypeMap.put(String.class, JsonDataModelInjector::inhaleText);
+ inhaleTypeMap.put(Integer.class, JsonDataModelInjector::inhaleInteger);
+ inhaleTypeMap.put(Boolean.class, JsonDataModelInjector::inhaleBoolean);
+ inhaleTypeMap.put(JsonNode.class, JsonDataModelInjector::inhaleJsonNode);
+ inhaleTypeMap.put(ArrayNode.class, JsonDataModelInjector::inhaleArrayNode);
+ inhaleTypeMap.put(ObjectNode.class, JsonDataModelInjector::inhaleObjectNode);
+ }
+
+ /**
+ * Inhales data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private void inhaleModel(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ DataModelFieldBehavior behavior = inhaleTypeMap.get(field.getType());
+ if (Objects.isNull(behavior)) {
+ throw new WorkflowException("Not supported type(" + field.getType() + ")");
+ }
+ behavior.apply(worklet, context, field, model);
+ }
+
+ /**
+ * Inhales text data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model text data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void inhaleText(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ if (!(Objects.equals(field.getType(), String.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not String");
+ }
+
+ String text;
+ try {
+ field.setAccessible(true);
+ text = (String) field.get(worklet);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+
+ if (Objects.isNull(text)) {
+ return;
+ }
+
+ JsonDataModelTree tree = (JsonDataModelTree) context.data();
+ JsonNode jsonNode = tree.nodeAt(model.path());
+
+ if (Objects.isNull(jsonNode) || jsonNode instanceof MissingNode) {
+ tree.setAt(model.path(), text);
+ } else if (!(jsonNode instanceof TextNode)) {
+ throw new WorkflowException("Invalid text data model on (" + model.path() + ")");
+ } else {
+ tree.remove(model.path());
+ tree.setAt(model.path(), text);
+ }
+ }
+
+ /**
+ * Inhales integer data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model integer data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void inhaleInteger(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+ if (!(Objects.equals(field.getType(), Integer.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not Integer");
+ }
+
+ Integer number;
+ try {
+ field.setAccessible(true);
+ number = (Integer) field.get(worklet);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+
+ if (Objects.isNull(number)) {
+ return;
+ }
+
+ JsonDataModelTree tree = (JsonDataModelTree) context.data();
+ JsonNode jsonNode = tree.nodeAt(model.path());
+
+ if (Objects.isNull(jsonNode) || jsonNode instanceof MissingNode) {
+ tree.setAt(model.path(), number);
+ } else if (!(jsonNode instanceof IntNode)) {
+ throw new WorkflowException("Invalid integer data model on (" + model.path() + ")");
+ } else {
+ tree.remove(model.path());
+ tree.setAt(model.path(), number);
+ }
+ }
+
+ /**
+ * Inhales boolean data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model boolean data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void inhaleBoolean(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ if (!(Objects.equals(field.getType(), Boolean.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not Boolean");
+ }
+
+ Boolean bool;
+ try {
+ field.setAccessible(true);
+ bool = (Boolean) field.get(worklet);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+
+ if (Objects.isNull(bool)) {
+ return;
+ }
+
+ JsonDataModelTree tree = (JsonDataModelTree) context.data();
+ JsonNode jsonNode = tree.nodeAt(model.path());
+
+ if (Objects.isNull(jsonNode) || jsonNode instanceof MissingNode) {
+ tree.setAt(model.path(), bool);
+ } else if (!(jsonNode instanceof BooleanNode)) {
+ throw new WorkflowException("Invalid boolean data model on (" + model.path() + ")");
+ } else {
+ tree.remove(model.path());
+ tree.setAt(model.path(), bool);
+ }
+ }
+
+ /**
+ * Inhales json node data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model json node data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void inhaleJsonNode(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+
+ if (!(Objects.equals(field.getType(), JsonNode.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not JsonNode");
+ }
+
+ JsonNode tgtJsonNode;
+ try {
+ field.setAccessible(true);
+ tgtJsonNode = (JsonNode) field.get(worklet);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+
+ if (Objects.isNull(tgtJsonNode)) {
+ return;
+ }
+
+ JsonDataModelTree tree = (JsonDataModelTree) context.data();
+ JsonNode jsonNode = tree.nodeAt(model.path());
+
+ if (Objects.isNull(jsonNode) || jsonNode instanceof MissingNode) {
+ tree.attach(model.path(), new JsonDataModelTree(tgtJsonNode));
+ } else if (!(jsonNode instanceof JsonNode)) {
+ throw new WorkflowException("Invalid json node data model on (" + model.path() + ")");
+ } else {
+ // do nothing
+ }
+ }
+
+ /**
+ * Inhales json array node data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model json array node data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void inhaleArrayNode(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+ if (!(Objects.equals(field.getType(), ArrayNode.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not ArrayNode");
+ }
+
+ ArrayNode tgtArrayNode;
+ try {
+ field.setAccessible(true);
+ tgtArrayNode = (ArrayNode) field.get(worklet);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+
+ if (Objects.isNull(tgtArrayNode)) {
+ return;
+ }
+
+ JsonDataModelTree tree = (JsonDataModelTree) context.data();
+ JsonNode jsonNode = tree.nodeAt(model.path());
+
+ if (Objects.isNull(jsonNode) || jsonNode instanceof MissingNode) {
+ tree.attach(model.path(), new JsonDataModelTree(tgtArrayNode));
+ } else if (!(jsonNode instanceof ArrayNode)) {
+ throw new WorkflowException("Invalid array node data model on (" + model.path() + ")");
+ } else {
+ // do nothing
+ }
+ }
+
+ /**
+ * Inhales json object node data model on the filed of work-let.
+ *
+ * @param worklet work-let
+ * @param context workflow context
+ * @param field the field of work-let
+ * @param model json object node data model for the field
+ * @throws WorkflowException workflow exception
+ */
+ private static void inhaleObjectNode(Worklet worklet, WorkflowContext context, Field field, JsonDataModel model)
+ throws WorkflowException {
+ if (!(Objects.equals(field.getType(), ObjectNode.class))) {
+ throw new WorkflowException("Target field (" + field + ") is not ObjectNode");
+ }
+
+ ObjectNode tgtObjNode;
+ try {
+ field.setAccessible(true);
+ tgtObjNode = (ObjectNode) field.get(worklet);
+ } catch (IllegalAccessException e) {
+ throw new WorkflowException(e);
+ }
+
+ if (Objects.isNull(tgtObjNode)) {
+ return;
+ }
+
+ JsonDataModelTree tree = (JsonDataModelTree) context.data();
+ JsonNode jsonNode = tree.nodeAt(model.path());
+
+ if (Objects.isNull(jsonNode) || jsonNode instanceof MissingNode) {
+ tree.attach(model.path(), new JsonDataModelTree(tgtObjNode));
+ } else if (!(jsonNode instanceof ObjectNode)) {
+ throw new WorkflowException("Invalid object node data model on (" + model.path() + ")");
+ } else {
+ // do nothing
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModelTree.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModelTree.java
new file mode 100644
index 0000000..7ee1be7
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/JsonDataModelTree.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.core.JsonPointer;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.BooleanNode;
+import com.fasterxml.jackson.databind.node.IntNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.fasterxml.jackson.databind.node.MissingNode;
+import com.fasterxml.jackson.databind.node.NumericNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import com.google.common.base.MoreObjects;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Objects;
+
+/**
+ * Class for json data model tree.
+ */
+public final class JsonDataModelTree implements DataModelTree {
+
+ private static final Logger log = LoggerFactory.getLogger(JsonDataModelTree.class);
+
+ /**
+ * Root node of json data model tree.
+ */
+ private JsonNode root;
+
+ /**
+ * Constructor of JsonDataModelTree.
+ */
+ public JsonDataModelTree() {
+ this.root = JsonNodeFactory.instance.objectNode();
+ }
+
+ /**
+ * Constructor of JsonDataModelTree.
+ * @param root root node of json data model tree
+ */
+ public JsonDataModelTree(JsonNode root) {
+ this.root = root;
+ }
+
+ @Override
+ public DataModelTree subtree(String path) {
+ JsonNode node = root.at(path);
+ if (Objects.isNull(node) || node.isMissingNode()) {
+ return null;
+ }
+ return new JsonDataModelTree(node);
+ }
+
+ @Override
+ public void attach(String path, DataModelTree tree) throws WorkflowException {
+
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+
+ JsonPointer ptr = JsonPointer.compile(path);
+
+ if (!(tree instanceof JsonDataModelTree)) {
+ throw new WorkflowException("Invalid subTree(" + tree + ")");
+ }
+ JsonNode attachingNode = ((JsonDataModelTree) tree).root();
+
+ attach(ptr, attachingNode);
+ }
+
+ private void attach(JsonPointer ptr, JsonNode attachingNode) throws WorkflowException {
+
+ JsonNode node = root.at(ptr);
+ if (!(node instanceof MissingNode)) {
+ throw new WorkflowException("Path(" + ptr + ") has already subtree(" + node + ")");
+ }
+
+ if (ptr.last().getMatchingIndex() != -1) {
+
+ alloc(ptr.head(), Nodetype.ARRAY);
+ JsonNode parentNode = root.at(ptr.head());
+ if (!parentNode.isArray()) {
+ throw new WorkflowException("Invalid parentNode type(" + parentNode.getNodeType() + " != Array)");
+ }
+ int index = ptr.last().getMatchingIndex();
+ ((ArrayNode) parentNode).insert(index, attachingNode);
+
+ } else if (ptr.last().getMatchingProperty() != null) {
+
+ alloc(ptr.head(), Nodetype.MAP);
+ JsonNode parentNode = root.at(ptr.head());
+ if (!parentNode.isObject()) {
+ throw new WorkflowException("Invalid parentNode type(" + parentNode.getNodeType() + " != Object)");
+ }
+ String key = ptr.last().getMatchingProperty();
+ ((ObjectNode) parentNode).put(key, attachingNode);
+
+ } else {
+ throw new WorkflowException("Invalid path(" + ptr + ")");
+ }
+ }
+
+ @Override
+ public void remove(String path) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ remove(ptr);
+ }
+
+ private void remove(JsonPointer ptr) throws WorkflowException {
+
+ JsonNode node = root.at(ptr);
+ if (node instanceof MissingNode) {
+ log.warn("{} does not have valid node", ptr);
+ return;
+ }
+
+ if (ptr.last().getMatchingIndex() != -1) {
+
+ JsonNode parentNode = root.at(ptr.head());
+ if (!parentNode.isArray()) {
+ throw new WorkflowException("Invalid parentNode type(" + parentNode.getNodeType() + " != Array)");
+ }
+ int index = ptr.last().getMatchingIndex();
+ ((ArrayNode) parentNode).remove(index);
+
+ } else if (ptr.last().getMatchingProperty() != null) {
+
+ JsonNode parentNode = root.at(ptr.head());
+ if (!parentNode.isObject()) {
+ throw new WorkflowException("Invalid parentNode type(" + parentNode.getNodeType() + " != Object)");
+ }
+ String key = ptr.last().getMatchingProperty();
+ ((ObjectNode) parentNode).remove(key);
+
+ } else {
+ throw new WorkflowException("Invalid path(" + ptr + ")");
+ }
+ }
+
+ @Override
+ public JsonDataModelTree alloc(String path, Nodetype leaftype) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+
+ JsonPointer ptr = JsonPointer.compile(path);
+ return alloc(ptr, leaftype);
+ }
+
+ /**
+ * Allocates json data model tree on json pointer path with specific leaf type.
+ * @param ptr json pointer to allocate
+ * @param leaftype type of leaf node
+ * @return json data model tree
+ * @throws WorkflowException workflow exception
+ */
+ private JsonDataModelTree alloc(JsonPointer ptr, Nodetype leaftype) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+
+ switch (leaftype) {
+ case MAP:
+ alloc(root, ptr, JsonNodeType.OBJECT);
+ break;
+ case ARRAY:
+ alloc(root, ptr, JsonNodeType.ARRAY);
+ break;
+ default:
+ throw new WorkflowException("Not supported leaftype(" + leaftype + ")");
+ }
+ return this;
+ }
+
+ /**
+ * Gets root json node.
+ * @return root json node
+ * @throws WorkflowException workflow exception
+ */
+ public JsonNode root() throws WorkflowException {
+ return nodeAt("");
+ }
+
+ /**
+ * Gets root json node as ObjectNode (MAP type).
+ * @return root json node as ObjectNode
+ * @throws WorkflowException workflow exception
+ */
+ public ObjectNode rootObject() throws WorkflowException {
+ return objectAt("");
+ }
+
+ /**
+ * Gets root json node as ArrayNode (Array type).
+ * @return root json node as ArrayNode
+ * @throws WorkflowException workflow exception
+ */
+ public ArrayNode rootArray() throws WorkflowException {
+ return arrayAt("");
+ }
+
+ /**
+ * Gets json node on specific path.
+ * @param path path of json node
+ * @return json node on specific path
+ * @throws WorkflowException workflow exception
+ */
+ public JsonNode nodeAt(String path) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ return nodeAt(ptr);
+ }
+
+ /**
+ * Gets json node on specific json pointer.
+ * @param ptr json pointer
+ * @return json node on specific json pointer.
+ * @throws WorkflowException workflow exception
+ */
+ public JsonNode nodeAt(JsonPointer ptr) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+ JsonNode node = root.at(ptr);
+ return node;
+ }
+
+ /**
+ * Gets json node on specific path as ObjectNode.
+ * @param path path of json node
+ * @return ObjectNode type json node on specific path
+ * @throws WorkflowException workflow exception
+ */
+ public ObjectNode objectAt(String path) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ return objectAt(ptr);
+ }
+
+ /**
+ * Gets json node on specific json pointer as ObjectNode.
+ * @param ptr json pointer
+ * @return ObjectNode type json node on specific json pointer.
+ * @throws WorkflowException workflow exception
+ */
+ public ObjectNode objectAt(JsonPointer ptr) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+ JsonNode node = root.at(ptr);
+ if (node instanceof MissingNode) {
+ return null;
+ }
+ if (!(node instanceof ObjectNode)) {
+ throw new WorkflowException("Invalid node(" + node + ") at " + ptr);
+ }
+ return (ObjectNode) node;
+ }
+
+ /**
+ * Gets json node on specific path as ArrayNode.
+ * @param path path of json node
+ * @return ArrayNode type json node on specific path
+ * @throws WorkflowException workflow exception
+ */
+ public ArrayNode arrayAt(String path) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ return arrayAt(ptr);
+ }
+
+ /**
+ * Gets json node on specific json pointer as ArrayNode.
+ * @param ptr json pointer
+ * @return ArrayNode type json node on specific json pointer.
+ * @throws WorkflowException workflow exception
+ */
+ public ArrayNode arrayAt(JsonPointer ptr) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+ JsonNode node = root.at(ptr);
+ if (node instanceof MissingNode) {
+ return null;
+ }
+ if (!(node instanceof ArrayNode)) {
+ throw new WorkflowException("Invalid node(" + node + ") at " + ptr);
+ }
+ return (ArrayNode) node;
+ }
+
+ /**
+ * Gets text node on specific path.
+ * @param path path of json node
+ * @return text on specific path
+ * @throws WorkflowException workflow exception
+ */
+ public String textAt(String path) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ return textAt(ptr);
+ }
+
+ /**
+ * Gets text on specific json pointer.
+ * @param ptr json pointer
+ * @return text on specific json pointer
+ * @throws WorkflowException workflow exception
+ */
+ public String textAt(JsonPointer ptr) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+ JsonNode node = root.at(ptr);
+ if (node instanceof MissingNode) {
+ return null;
+ }
+ if (!(node instanceof TextNode)) {
+ throw new WorkflowException("Invalid node(" + node + ") at " + ptr);
+ }
+ return ((TextNode) node).asText();
+ }
+
+ /**
+ * Gets integer node on specific path.
+ * @param path path of json node
+ * @return integer on specific path
+ * @throws WorkflowException workflow exception
+ */
+ public Integer intAt(String path) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ return intAt(ptr);
+ }
+
+ /**
+ * Gets integer on specific json pointer.
+ * @param ptr json pointer
+ * @return integer on specific json pointer
+ * @throws WorkflowException workflow exception
+ */
+ public Integer intAt(JsonPointer ptr) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+ JsonNode node = root.at(ptr);
+ if (node instanceof MissingNode) {
+ return null;
+ }
+ if (!(node instanceof NumericNode)) {
+ throw new WorkflowException("Invalid node(" + node + ") at " + ptr);
+ }
+ return ((NumericNode) node).asInt();
+ }
+
+ /**
+ * Gets boolean on specific path.
+ * @param path path of json node
+ * @return boolean on specific path
+ * @throws WorkflowException workflow exception
+ */
+ public Boolean booleanAt(String path) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ return booleanAt(ptr);
+ }
+
+ /**
+ * Gets boolean on specific json pointer.
+ * @param ptr json pointer
+ * @return boolean on specific json pointer
+ * @throws WorkflowException workflow exception
+ */
+ public Boolean booleanAt(JsonPointer ptr) throws WorkflowException {
+ if (root == null || root instanceof MissingNode) {
+ throw new WorkflowException("Invalid root node");
+ }
+ JsonNode node = root.at(ptr);
+ if (node instanceof MissingNode) {
+ return null;
+ }
+ if (!(node instanceof BooleanNode)) {
+ throw new WorkflowException("Invalid node(" + node + ") at " + ptr);
+ }
+ return ((BooleanNode) node).asBoolean();
+ }
+
+ /**
+ * Sets text on specific json path.
+ * @param path json path
+ * @param text text to set
+ * @throws WorkflowException workflow exception
+ */
+ public void setAt(String path, String text) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ setAt(ptr, text);
+ }
+
+ /**
+ * Sets text on the specific json pointer.
+ * @param ptr json pointer
+ * @param text text to set
+ * @throws WorkflowException workflow exception
+ */
+ public void setAt(JsonPointer ptr, String text) throws WorkflowException {
+ TextNode textNode = TextNode.valueOf(text);
+ attach(ptr, textNode);
+ }
+
+ /**
+ * Sets boolean on specific json path.
+ * @param path json path
+ * @param isTrue boolean to set
+ * @throws WorkflowException workflow exception
+ */
+ public void setAt(String path, Boolean isTrue) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ setAt(ptr, isTrue);
+ }
+
+ /**
+ * Sets boolean on the specific json pointer.
+ * @param ptr json pointer
+ * @param isTrue boolean to set
+ * @throws WorkflowException workflow exception
+ */
+ public void setAt(JsonPointer ptr, Boolean isTrue) throws WorkflowException {
+ BooleanNode booleanNode = BooleanNode.valueOf(isTrue);
+ attach(ptr, booleanNode);
+ }
+
+ /**
+ * Sets integer on specific json path.
+ * @param path json path
+ * @param number number to set
+ * @throws WorkflowException workflow exception
+ */
+ public void setAt(String path, Integer number) throws WorkflowException {
+ JsonPointer ptr = JsonPointer.compile(path);
+ setAt(ptr, number);
+ }
+
+ /**
+ * Sets integer on the specific json pointer.
+ * @param ptr json pointer
+ * @param number number to set
+ * @throws WorkflowException workflow exception
+ */
+ public void setAt(JsonPointer ptr, Integer number) throws WorkflowException {
+ IntNode intNode = IntNode.valueOf(number);
+ attach(ptr, intNode);
+ }
+
+ /**
+ * Allocates json data model tree on json pointer path with specific leaf type.
+ * @param node current json node in the json tree path
+ * @param ptr json pointer
+ * @param leaftype leaf type to be allocated
+ * @return allocated json node
+ * @throws WorkflowException workflow exception
+ */
+ private JsonNode alloc(JsonNode node, JsonPointer ptr, JsonNodeType leaftype) throws WorkflowException {
+
+ if (ptr.matches()) {
+ if (node == null || node instanceof MissingNode) {
+ node = createEmpty(leaftype);
+ } else {
+ //TODO: checking existing node type is matched with leaftype
+ if (!Objects.equals(node.getNodeType(), leaftype)) {
+ throw new WorkflowException("Requesting leaftype(" + leaftype + ") is not matched with "
+ + "existing nodetype(" + node.getNodeType() + ") for " + ptr);
+ }
+ }
+ return node;
+ }
+
+ if (ptr.getMatchingIndex() != -1) {
+ if (node == null || node instanceof MissingNode) {
+ node = createEmpty(JsonNodeType.ARRAY);
+ }
+ JsonNode child = alloc(node.get(ptr.getMatchingIndex()), ptr.tail(), leaftype);
+ if (!node.has(ptr.getMatchingIndex())) {
+ ((ArrayNode) node).insert(ptr.getMatchingIndex(), child);
+ }
+ } else if (ptr.getMatchingProperty() != null) {
+ if (node == null || node instanceof MissingNode) {
+ node = createEmpty(JsonNodeType.OBJECT);
+ }
+ JsonNode child = alloc(node.get(ptr.getMatchingProperty()), ptr.tail(), leaftype);
+ if (!node.has(ptr.getMatchingProperty())) {
+ ((ObjectNode) node).put(ptr.getMatchingProperty(), child);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Creating empty json node.
+ * @param type json node type to create
+ * @return created json node
+ * @throws WorkflowException workflow exception
+ */
+ private JsonNode createEmpty(JsonNodeType type) throws WorkflowException {
+ if (type == JsonNodeType.OBJECT) {
+ return JsonNodeFactory.instance.objectNode();
+ } else if (type == JsonNodeType.ARRAY) {
+ return JsonNodeFactory.instance.arrayNode();
+ } else if (type == JsonNodeType.STRING) {
+ return JsonNodeFactory.instance.textNode("");
+ } else {
+ throw new WorkflowException("Not supported JsonNodetype(" + type + ")");
+ }
+ }
+
+ /**
+ * Gets the pretty json formatted string of this json data model tree.
+ * @return pretty json formatted string of this json data model tree
+ */
+ public String formattedRootString() {
+ String str = "";
+ try {
+ str = (new ObjectMapper()).writerWithDefaultPrettyPrinter().writeValueAsString(root);
+ } catch (JsonProcessingException e) {
+ log.error("Exception: ", e);
+ }
+ return str;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("json", root)
+ .toString();
+ }
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ProgramCounter.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ProgramCounter.java
new file mode 100644
index 0000000..6af50e0
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ProgramCounter.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018-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.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * An interface representing workflow program counter.
+ */
+public final class ProgramCounter {
+
+ public static final ProgramCounter INIT_PC = ProgramCounter.valueOf(Worklet.Common.INIT.name(), 0);
+
+ /**
+ * index of the worklet.
+ */
+ private int workletIndex;
+
+ /**
+ * Type of worklet.
+ */
+ private String workletType;
+
+ /**
+ * Index of worklet.
+ * @return index of worklet
+ */
+ public int workletIndex() {
+ return this.workletIndex;
+ }
+
+ /**
+ * Type of worklet.
+ * @return type of worklet
+ */
+ public String workletType() {
+ return this.workletType;
+ }
+
+ /**
+ * Constructor of workflow Program Counter.
+ * @param workletType type of worklet
+ * @param workletIndex index of worklet
+ */
+ private ProgramCounter(String workletType, int workletIndex) {
+ this.workletType = workletType;
+ this.workletIndex = workletIndex;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.toString());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ProgramCounter)) {
+ return false;
+ }
+ return Objects.equals(this.workletType(), ((ProgramCounter) obj).workletType())
+ && Objects.equals(this.workletIndex(), ((ProgramCounter) obj).workletIndex());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("(%d)%s", workletIndex, workletType);
+ }
+
+ /**
+ * Builder of workflow Program Counter.
+ * @param workletType type of worklet
+ * @param workletIndex index of worklet
+ * @return program counter
+ */
+ public static ProgramCounter valueOf(String workletType, int workletIndex) {
+ return new ProgramCounter(workletType, workletIndex);
+ }
+
+ /**
+ * Builder of workflow Program Counter.
+ * @param strProgramCounter string format for program counter
+ * @return program counter
+ */
+ public static ProgramCounter valueOf(String strProgramCounter) {
+
+ Matcher m = Pattern.compile("\\((\\d+)\\)(.+)").matcher(strProgramCounter);
+
+ if (!m.matches()) {
+ throw new IllegalArgumentException("Malformed program counter string");
+ }
+
+ return new ProgramCounter(m.group(2), Integer.parseInt(m.group(1)));
+ }
+
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/RpcDescription.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/RpcDescription.java
new file mode 100644
index 0000000..5b067b4
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/RpcDescription.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Interface for workflow RPC description.
+ */
+public interface RpcDescription {
+
+ /**
+ * Workflow RPC operation pointer.
+ */
+ String RPC_OP_PTR = "/op";
+
+ /**
+ * Workflow RPC parameters pointer.
+ */
+ String RPC_PARAMS_PTR = "/params";
+
+ /**
+ * Workflow RPC invocation ID pointer.
+ */
+ String RPC_ID_PTR = "/id";
+
+ /**
+ * Returns workflow RPC operation.
+ * @return workflow RPC operation
+ */
+ String op();
+
+ /**
+ * Returns workflow RPC parameters.
+ * @return workflow RPC parameters
+ */
+ JsonNode params();
+
+ /**
+ * Returns workflow RPC invocation ID.
+ * @return workflow RPC invocation ID
+ */
+ String id();
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/SystemWorkflowContext.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/SystemWorkflowContext.java
new file mode 100644
index 0000000..4cc15bd
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/SystemWorkflowContext.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+
+/**
+ * WorkflowContext for system workflow.
+ */
+public class SystemWorkflowContext extends DefaultWorkflowContext {
+
+ /**
+ * Timestamp when this system workflow context was created.
+ */
+ private final long timestamp;
+
+ /**
+ * Distributor string for designating which onos node executes this workflow context with work partition.
+ */
+ private String distributor;
+
+ /**
+ * The constructor of SystemWorkflowContext.
+ * @param builder builder of SystemWorkflowContext
+ */
+ public SystemWorkflowContext(Builder builder) {
+ super(builder);
+ timestamp = System.currentTimeMillis();
+ //initial distributor(It can be changed)
+ distributor = name();
+ }
+
+ @Override
+ public String distributor() {
+ return distributor;
+ }
+
+ /**
+ * Sets distributor string of this workflow context.
+ * @param distributor distributor string
+ */
+ public void setDistributor(String distributor) {
+ this.distributor = distributor;
+ }
+
+ @Override
+ public String name() {
+ return workflowId().toString()
+ + ":" + timestamp
+ + "@" + workplaceName();
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("name", name())
+ .add("triggernext", triggerNext())
+ .add("data", data())
+ .add("current", current())
+ .add("state", state())
+ .add("cause", cause())
+ .toString();
+ }
+
+ /**
+ * Gets systemBuilder instance.
+ * @return systemBuilder instance
+ */
+ public static final Builder systemBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for system workflow context.
+ */
+ public static class Builder extends DefaultWorkflowContext.Builder {
+
+ /**
+ * Builds system workflow context.
+ * @return instance of default workflow context.
+ */
+ public SystemWorkflowContext build() {
+ return new SystemWorkflowContext(this);
+ }
+ }
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/TimeoutTask.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/TimeoutTask.java
new file mode 100644
index 0000000..180d9eb
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/TimeoutTask.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018-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 com.google.common.base.MoreObjects;
+
+import static org.onosproject.workflow.api.CheckCondition.check;
+
+
+public final class TimeoutTask extends HandlerTask {
+
+ private TimeoutTask(Builder builder) {
+ super(builder);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("context", context())
+ .add("programCounter", programCounter())
+ .toString();
+ }
+
+ /**
+ * Gets a instance of builder.
+ * @return instance of builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of TimeoutTask.
+ */
+ public static class Builder extends HandlerTask.Builder {
+ @Override
+ public Builder context(WorkflowContext context) {
+ super.context(context);
+ return this;
+ }
+
+ @Override
+ public Builder programCounter(ProgramCounter programCounter) {
+ super.programCounter(programCounter);
+ return this;
+ }
+
+ /**
+ * Builds TimeoutTask.
+ * @return instance of TimeoutTask
+ * @throws WorkflowException workflow exception
+ */
+ public TimeoutTask build() throws WorkflowException {
+ check(context != null, "context is invalid");
+ check(programCounter != null, "programCounter is invalid");
+ return new TimeoutTask(this);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/TimerChain.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/TimerChain.java
new file mode 100644
index 0000000..afa2ac6
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/TimerChain.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2018-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.Date;
+import java.util.Objects;
+import java.util.PriorityQueue;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Class for time chain timer.
+ */
+public class TimerChain {
+
+ private PriorityQueue<TimerChainTask> taskQueue = new PriorityQueue<>();
+
+ private Timer impendingTimer;
+ private TimerChainTask impendingTask;
+
+ /**
+ * Constructor of timer chain.
+ */
+ public TimerChain() {
+
+ }
+
+ /**
+ * Schedules timer event.
+ * @param afterMs millisecond which time event happens.
+ * @param runnable runnable to be executed after 'afterMs'
+ */
+ public void schedule(long afterMs, Runnable runnable) {
+ schedule(new Date((new Date()).getTime() + afterMs), runnable);
+ }
+
+ /**
+ * Schedules timer event.
+ * @param date date which timer event happens.
+ * @param runnable runnable to be executed on 'date'
+ */
+ public void schedule(Date date, Runnable runnable) {
+ schedule(new TimerChainTask(this, date, runnable));
+ }
+
+ /**
+ * Schedule timer chain task.
+ * @param task task to be scheduled.
+ */
+ private void schedule(TimerChainTask task) {
+ synchronized (this) {
+ if (taskQueue.isEmpty()) {
+ scheduleImpending(task);
+ return;
+ }
+
+ if (task.date().getTime() < head().date().getTime()) {
+ impendingTimer.cancel();
+ impendingTask.cancel();
+ TimerChainTask prevImpendingTask = pop().copy();
+ taskQueue.offer(prevImpendingTask);
+
+ scheduleImpending(task);
+ } else {
+ taskQueue.offer(task);
+ }
+ }
+ }
+
+ /**
+ * Schedule impending timer task.
+ * @param task impending timer chain task
+ * @return timer chain task
+ */
+ private TimerChainTask scheduleImpending(TimerChainTask task) {
+ taskQueue.offer(task);
+ Timer timer = new Timer();
+ this.setImpendingTask(task);
+ this.setImpendingTimer(timer);
+ timer.schedule(task, task.date());
+ return task;
+ }
+
+ /**
+ * Gets impending timer.
+ * @return impending timer
+ */
+ public Timer implendingTimer() {
+ return impendingTimer;
+ }
+
+ /**
+ * Sets impending timer.
+ * @param impendingTimer impending timer
+ */
+ public void setImpendingTimer(Timer impendingTimer) {
+ this.impendingTimer = impendingTimer;
+ }
+
+ /**
+ * Gets impending timer task.
+ * @return impending timer task
+ */
+ public TimerTask impendingTask() {
+ return impendingTask;
+ }
+
+ /**
+ * Sets impending timer task.
+ * @param impendingTask impending timer task
+ */
+ public void setImpendingTask(TimerChainTask impendingTask) {
+ this.impendingTask = impendingTask;
+ }
+
+ /**
+ * Gets head of timer chain task queue.
+ * @return timer chain task
+ */
+ public TimerChainTask head() {
+ if (!taskQueue.isEmpty()) {
+ return taskQueue.peek();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Pops head of timer chain task queue.
+ * @return timer chain task
+ */
+ public TimerChainTask pop() {
+ if (!taskQueue.isEmpty()) {
+ return taskQueue.poll();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Class for timer chain task.
+ */
+ public static class TimerChainTask extends TimerTask implements Comparable<TimerChainTask> {
+
+ private final TimerChain timerchain;
+ private final Date date;
+ private final Runnable runnable;
+
+ /**
+ * Constructor of timer chain task.
+ * @param timerchain timer chain
+ * @param date date to be scheduled
+ * @param runnable runnable to be executed by timer
+ */
+ public TimerChainTask(TimerChain timerchain, Date date, Runnable runnable) {
+ this.timerchain = timerchain;
+ this.date = date;
+ this.runnable = runnable;
+ }
+
+ /**
+ * Gets date.
+ * @return date of timer chain task
+ */
+ public Date date() {
+ return this.date;
+ }
+
+ /**
+ * Gets runnable.
+ * @return runnable of timer chain task
+ */
+ public Runnable runnable() {
+ return this.runnable;
+ }
+
+ @Override
+ public void run() {
+
+ TimerChainTask nextTask;
+ synchronized (timerchain) {
+ if (timerchain.impendingTask() != this) {
+ runnable().run();
+ return;
+ }
+
+ timerchain.implendingTimer().cancel();
+ timerchain.pop();
+
+ nextTask = timerchain.head();
+
+ if (nextTask != null) {
+ Timer nextTimer = new Timer();
+ this.timerchain.setImpendingTask(nextTask);
+ this.timerchain.setImpendingTimer(nextTimer);
+ nextTimer.schedule(nextTask, nextTask.date());
+ }
+ }
+
+ runnable().run();
+
+ }
+
+ @Override
+ public int compareTo(TimerChainTask target) {
+ return date().compareTo(target.date());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof TimerChainTask)) {
+ return false;
+ }
+ TimerChainTask that = (TimerChainTask) o;
+
+ return this.date().equals(that.date());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(date);
+ }
+
+ /**
+ * Copies timer chain task.
+ * @return timer chain task
+ */
+ public TimerChainTask copy() {
+ return new TimerChainTask(timerchain, date, runnable);
+ }
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkExecutor.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkExecutor.java
new file mode 100644
index 0000000..e834e81
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018-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;
+
+/**
+ * Functional interface for delivering method reference of worklet completion event generator.
+ */
+@FunctionalInterface
+public interface WorkExecutor {
+
+ /**
+ * Applies this method reference.
+ * @throws WorkflowException workflow exception
+ */
+ void apply() throws WorkflowException;
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workflow.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workflow.java
new file mode 100644
index 0000000..848a706
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workflow.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018-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.net.URI;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An interface representing workflow.
+ */
+public interface Workflow {
+
+ /**
+ * Id of workflow.
+ * @return id
+ */
+ URI id();
+
+ /**
+ * Returns init worklet.
+ * @param context workflow context
+ * @return init worklet
+ * @throws WorkflowException workflow exception
+ */
+ Worklet init(WorkflowContext context) throws WorkflowException;
+
+ /**
+ * Returns next program counter.
+ * @param context workflow context
+ * @return next program counter
+ * @throws WorkflowException workflow exception
+ */
+ ProgramCounter next(WorkflowContext context) throws WorkflowException;
+
+ /**
+ * Gets increased program coounter.
+ * @param pc program counter
+ * @return increased program counter
+ * @throws WorkflowException workflow exception
+ */
+ ProgramCounter increased(ProgramCounter pc) throws WorkflowException;
+
+ /**
+ * Returns instance of worklet.
+ * @param workletType class name of worklet
+ * @return instance of worklet
+ * @throws WorkflowException workflow exception
+ */
+ Worklet getWorkletInstance(String workletType) throws WorkflowException;
+
+ /**
+ * Builds workflow context.
+ * @param workplace workplace of system workflow
+ * @param data data model of system workflow context
+ * @return workflow context
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowContext buildContext(Workplace workplace, DataModelTree data) throws WorkflowException;
+
+ /**
+ * Builds system workflow context.
+ * @param workplace workplace of system workflow
+ * @param data data model of system workflow context
+ * @return system workflow context
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowContext buildSystemContext(Workplace workplace, DataModelTree data) throws WorkflowException;
+
+ /**
+ * Returns workflow attributes.
+ * @return attributes
+ */
+ Set<WorkflowAttribute> attributes();
+
+ /**
+ * Returns worklet type list.
+ * @return worklet type
+ */
+ List<String> getWorkletTypeList();
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowAttribute.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowAttribute.java
new file mode 100644
index 0000000..18ed701
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowAttribute.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018-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;
+
+/**
+ * Attributes of workflow.
+ */
+public enum WorkflowAttribute {
+
+ /**
+ * Removes workflow context after completion of workflow.
+ */
+ REMOVE_AFTER_COMPLETE,
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowBatchDelegate.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowBatchDelegate.java
new file mode 100644
index 0000000..d54a92a
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowBatchDelegate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018-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 com.google.common.annotations.Beta;
+
+import java.util.Collection;
+
+/**
+ * Facade for receiving notifications from the workflow batch service.
+ */
+@Beta
+public interface WorkflowBatchDelegate {
+
+ /**
+ * Submits the specified batch of workflow operations for processing.
+ *
+ * @param operations batch of operations
+ */
+ void execute(Collection<WorkflowData> operations);
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowContext.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowContext.java
new file mode 100644
index 0000000..836524d
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowContext.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2018-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 org.onosproject.event.Event;
+
+import java.net.URI;
+import java.util.Set;
+
+/**
+ * An abstract class representing WorkflowContext.
+ */
+public abstract class WorkflowContext extends WorkflowData {
+
+ /**
+ * Constructor of workflow context.
+ * @param data data model tree
+ */
+ public WorkflowContext(DataModelTree data) {
+ super(data);
+ }
+
+ /**
+ * Returns workflow id of this workflow context.
+ * @return workflow id
+ */
+ public abstract URI workflowId();
+
+ /**
+ * Returns workplace name.
+ * @return workplace name
+ */
+ public abstract String workplaceName();
+
+ /**
+ * Returns the current state of workflow context.
+ * @return current state of workflow context
+ */
+ public abstract WorkflowState state();
+
+ /**
+ * Sets the current state of workflow context.
+ * @param state current state of workflow context
+ */
+ public abstract void setState(WorkflowState state);
+
+ /**
+ * Sets the current program counter of workflow context.
+ * @param pc current program counter
+ */
+ public abstract void setCurrent(ProgramCounter pc);
+
+ /**
+ * Returns the current program counter of workflow.
+ * @return the current program counter of workflow
+ */
+ public abstract ProgramCounter current();
+
+ /**
+ * Returns the cause string of exception state.
+ * @return cause string
+ */
+ public abstract String cause();
+
+ /**
+ * Sets the cause string of exception state.
+ * @param cause cause string
+ */
+ public abstract void setCause(String cause);
+
+ /**
+ * Indicates the worklet process become completed.
+ * By calling this, workflow triggers the next worklet selection
+ */
+ public abstract void completed();
+
+ /**
+ * Waits an event which have 'eventHint' after executing executor.
+ * If the event happens, Worklet.isCompleted will be called.
+ * If the event does not happen for timeoutMs, Worklet.timeout will be called.
+ * @param eventType the class of event to wait
+ * @param eventHint the event of the event to wait
+ * @param eventGenerator a method reference to be executed after executing executor
+ * @param timeoutMs timeout millisecond
+ */
+ public abstract void waitCompletion(Class<? extends Event> eventType, String eventHint,
+ WorkExecutor eventGenerator, long timeoutMs);
+
+
+ /**
+ * Waits an event which has any one of eventHint from Set 'eventHintSet' after executing executor.
+ * If the event happens, Worklet.isCompleted will be called.
+ * If the event does not happen for timeoutMs, Worklet.timeout will be called.
+ * @param eventType the class of event to wait
+ * @param eventHintSet the Set of eventHints of the event to wait
+ * @param eventGenerator a method reference to be executed after executing executor
+ * @param timeoutMs timeout millisecond
+ */
+ public abstract void waitAnyCompletion(Class<? extends Event> eventType, Set<String> eventHintSet,
+ WorkExecutor eventGenerator, long timeoutMs);
+
+
+ /**
+ * Waits timeout milliseconds. After timeoutMs Worklet.timeout will be called.
+ * @param timeoutMs timeout millisecond
+ */
+ public abstract void waitFor(long timeoutMs);
+
+ /**
+ * Returns the class of a completion event to wait.
+ * @return the class of a completion event
+ */
+ public abstract Class<? extends Event> completionEventType();
+
+ /**
+ * Returns the set of event hint string to wait.
+ * @return the event hint string set
+ */
+ public abstract Set<String> completionEventHints();
+
+ /**
+ * Returns method reference for generating completion event.
+ * @return a method reference
+ */
+ public abstract WorkExecutor completionEventGenerator();
+
+ /**
+ * Returns completion event timeout.
+ * @return completion event timeout
+ */
+ public abstract long completionEventTimeout();
+
+ /**
+ * Sets workflow service.
+ * @param workflowExecutionService workflow service
+ */
+ public abstract void setWorkflowExecutionService(WorkflowExecutionService workflowExecutionService);
+
+ /**
+ * Gets workflow service.
+ * @return workflow service
+ */
+ public abstract WorkflowExecutionService workflowService();
+
+ /**
+ * Sets workflow store.
+ * @param workflowStore workflow store.
+ */
+ public abstract void setWorkflowStore(WorkflowStore workflowStore);
+
+ /**
+ * Gets worklow store.
+ * @return workflow store
+ */
+ public abstract WorkflowStore workflowStore();
+
+ /**
+ * Sets workplace store.
+ * @param workplaceStore work place store.
+ */
+ public abstract void setWorkplaceStore(WorkplaceStore workplaceStore);
+
+ /**
+ * Gets workplace store.
+ * @return workplace store
+ */
+ public abstract WorkplaceStore workplaceStore();
+
+ /**
+ * Get service.
+ * @param serviceClass service class
+ * @param <T> service class type
+ * @return service reference
+ * @throws WorkflowException workflow exception
+ */
+ public abstract <T> T getService(Class<T> serviceClass) throws WorkflowException;
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowData.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowData.java
new file mode 100644
index 0000000..6a8590c
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowData.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018-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;
+
+
+/**
+ * An abstract class representing workflow data.
+ */
+public abstract class WorkflowData {
+
+ private DataModelTree data;
+ private boolean triggerNext = true; // default is true
+
+ /**
+ * Constructor of workflow data.
+ * @param data data model tree
+ */
+ public WorkflowData(DataModelTree data) {
+ this.data = data;
+ }
+
+ /**
+ * Returns name.
+ * @return name
+ */
+ public abstract String name();
+
+ /**
+ * Returns work-partition distributor.
+ * @return work-partition distributor
+ */
+ public abstract String distributor();
+
+ /**
+ * Returns context model tree.
+ * @return context model tree
+ */
+ public DataModelTree data() {
+ return data;
+ }
+
+ /**
+ * Returns whether to trigger next worklet selection.
+ * @return whether to trigger next worklet selection
+ */
+ public boolean triggerNext() {
+ return triggerNext;
+ }
+
+ /**
+ * Sets whether to handle update event.
+ * @param triggerNext whether to handle update event
+ */
+ public void setTriggerNext(boolean triggerNext) {
+ this.triggerNext = triggerNext;
+ }
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataEvent.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataEvent.java
new file mode 100644
index 0000000..4833251
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataEvent.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018-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 org.onosproject.event.AbstractEvent;
+
+/**
+ * Workflow data event class.
+ */
+public class WorkflowDataEvent extends AbstractEvent<WorkflowDataEvent.Type, WorkflowData> {
+
+ /**
+ * Workflow data event types.
+ */
+ public enum Type {
+
+ /**
+ * Insertion of workflow data.
+ */
+ INSERT,
+
+ /**
+ * Updation of workflow data.
+ */
+ UPDATE,
+
+ /**
+ * Removal of workflow data.
+ */
+ REMOVE
+ }
+
+ /**
+ * Constructor for workflow data event.
+ * @param type workflow data event type
+ * @param data workflow data
+ */
+ public WorkflowDataEvent(Type type, WorkflowData data) {
+ super(type, data);
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataListener.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataListener.java
new file mode 100644
index 0000000..b777e74
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataListener.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018-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 org.onosproject.event.EventListener;
+
+/**
+ * Interface for workflow data listener.
+ */
+public interface WorkflowDataListener extends EventListener<WorkflowDataEvent> {
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataModelException.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataModelException.java
new file mode 100644
index 0000000..7d17529
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDataModelException.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.fasterxml.jackson.databind.JsonNode;
+
+import java.net.URI;
+import java.util.List;
+
+/**
+ * Workflow DataModel exception class.
+ */
+public class WorkflowDataModelException extends WorkflowException {
+
+ private URI workflowId;
+ private JsonNode parameterJson;
+ private List<String> errorMsgs;
+
+ /**
+ * Default Constructor for Workflow DataModel Exception.
+ *
+ * @param msg exception message
+ */
+ public WorkflowDataModelException(String msg) {
+
+ super(msg);
+ }
+
+ /**
+ * Constructor for Workflow DataModel Exception.
+ *
+ * @param workflowId id of workflow
+ * @param parameterJson paramter json data model
+ * @param errorMsgs error message for json data model
+ */
+ public WorkflowDataModelException(URI workflowId, JsonNode parameterJson, List<String> errorMsgs) {
+ super("Invalid workflow data model: " +
+ " workflow: " + workflowId.toString() +
+ ", parameter json: " + parameterJson.toString() +
+ ", errors: " + errorMsgs);
+ this.workflowId = workflowId;
+ this.parameterJson = parameterJson;
+ this.errorMsgs = errorMsgs;
+ }
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDescription.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDescription.java
new file mode 100644
index 0000000..ca483f0
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowDescription.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+import java.net.URI;
+
+
+/**
+ * interface for workflow description.
+ */
+public interface WorkflowDescription {
+
+ /**
+ * Workflow workplace field name.
+ */
+ String WF_WORKPLACE = "workplace";
+
+ /**
+ * Workflow ID field name.
+ */
+ String WF_ID = "id";
+
+ /**
+ * Workflow data field name.
+ */
+ String WF_DATA = "data";
+
+ /**
+ * Gets workplace name.
+ * @return workplace name
+ */
+ String workplaceName();
+
+ /**
+ * Gets workflow ID.
+ * @return workflow ID
+ */
+ URI id();
+
+ /**
+ * Gets workflow context name.
+ * @return workflow context name
+ */
+ String workflowContextName();
+
+ /**
+ * Gets workflow data model.
+ * @return workflow data model
+ */
+ JsonNode data();
+
+ /**
+ * Gets json of workflow description.
+ * @return json of workflow description
+ */
+ JsonNode toJson();
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowException.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowException.java
new file mode 100644
index 0000000..09506bd
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowException.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018-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;
+
+/**
+ * Workflow exception class.
+ */
+public class WorkflowException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor for workflow exception.
+ * @param msg exception message
+ */
+ public WorkflowException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor for workflow exception.
+ * @param e throwable to deliver
+ */
+ public WorkflowException(Throwable e) {
+ super(e);
+ }
+
+ /**
+ * Constructor for workflow exception.
+ * @param msg exception message
+ * @param e throwable to deliver
+ */
+ public WorkflowException(String msg, Throwable e) {
+ super(msg, e);
+ }
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowExecutionService.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowExecutionService.java
new file mode 100644
index 0000000..c5e00a7
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowExecutionService.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018-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 org.onosproject.event.Event;
+import org.onosproject.event.ListenerService;
+
+import java.util.Set;
+
+/**
+ * Interface for workflow execution service.
+ */
+public interface WorkflowExecutionService extends ListenerService<WorkflowDataEvent, WorkflowDataListener> {
+
+ /**
+ * Executes init worklet.
+ * @param context workflow context
+ */
+ void execInitWorklet(WorkflowContext context);
+
+ /**
+ * Evals workflow context.
+ * @param contextName the name of workflow context
+ */
+ void eval(String contextName);
+
+ /**
+ * Triggers workflow event map.
+ * @param event triggering event
+ * @param generator event hint generation method reference
+ */
+ void eventMapTrigger(Event event, EventHintSupplier generator);
+
+ /**
+ * Registers workflow event map.
+ * @param eventType event type (class name of event)
+ * @param eventHintSet Set of event hint value
+ * @param contextName workflow context name to be called by this event map
+ * @param programCounterString worklet type to be called by this event map
+ * @throws WorkflowException workflow exception
+ */
+ void registerEventMap(Class<? extends Event> eventType, Set<String> eventHintSet,
+ String contextName, String programCounterString) throws WorkflowException;
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowService.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowService.java
new file mode 100644
index 0000000..b11e835
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Interface for workflow service.
+ */
+public interface WorkflowService {
+
+ /**
+ * Creates workplace.
+ * @param wpDesc workplace description
+ * @throws WorkflowException workflow exception
+ */
+ void createWorkplace(WorkplaceDescription wpDesc) throws WorkflowException;
+
+ /**
+ * Removes workplace.
+ * @param wpDesc workplace description
+ * @throws WorkflowException workflow exception
+ */
+ void removeWorkplace(WorkplaceDescription wpDesc) throws WorkflowException;
+
+ /**
+ * Clears all workplaces.
+ * @throws WorkflowException workflow exception
+ */
+ void clearWorkplace() throws WorkflowException;
+
+ /**
+ * Invokes workflow.
+ * @param wfDesc workflow description
+ * @throws WorkflowException workflow exception
+ */
+ void invokeWorkflow(WorkflowDescription wfDesc) throws WorkflowException;
+
+ /**
+ * Invokes workflow.
+ * @param worklowDescJson workflow description json
+ * @throws WorkflowException workflow exception
+ */
+ void invokeWorkflow(JsonNode worklowDescJson) throws WorkflowException;
+
+ /**
+ * Terminates workflow.
+ * @param wfDesc workflow description
+ * @throws WorkflowException workflow exception
+ */
+ void terminateWorkflow(WorkflowDescription wfDesc) throws WorkflowException;
+}
\ No newline at end of file
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowState.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowState.java
new file mode 100644
index 0000000..0f92624
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowState.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018-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;
+
+/**
+ * State of workflow.
+ */
+public enum WorkflowState {
+
+ /**
+ * Workflow is idle state.
+ */
+ IDLE,
+
+ /**
+ * Workflow is running state.
+ */
+ RUNNING,
+
+ /**
+ * Workflow is exception state.
+ */
+ EXCEPTION
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowStore.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowStore.java
new file mode 100644
index 0000000..ac0de4d
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkflowStore.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018-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.net.URI;
+import java.util.Collection;
+
+/**
+ * Store for managing workflow.
+ */
+public interface WorkflowStore {
+
+ /**
+ * Registers workflow.
+ * @param workflow registering workflow
+ */
+ void register(Workflow workflow);
+
+ /**
+ * Unregisters workflow.
+ * @param id id of workflow
+ */
+ void unregister(URI id);
+
+ /**
+ * Gets workflow.
+ * @param id id of workflow
+ * @return workflow
+ */
+ Workflow get(URI id);
+
+ /**
+ * Gets all workflow.
+ * @return collection of workflow
+ */
+ Collection<Workflow> getAll();
+
+ /**
+ * Registers local class loader.
+ * @param loader class loader
+ */
+ void registerLocal(ClassLoader loader);
+
+ /**
+ * Unregisters local class loader.
+ * @param loader class loader
+ */
+ void unregisterLocal(ClassLoader loader);
+
+ /**
+ * Gets class from registered class loaders.
+ * @param name name of class
+ * @return class
+ * @throws ClassNotFoundException class not found exception
+ */
+ Class getClass(String name) throws ClassNotFoundException;
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Worklet.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Worklet.java
new file mode 100644
index 0000000..c4b4fb2
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Worklet.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2018-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 org.onosproject.event.Event;
+
+/**
+ * An interface representing worklet. A workflow is composed of worklets.
+ */
+public interface Worklet {
+
+ int MAX_WORKS = 10000;
+
+ /**
+ * Returns tag name of worklet. class name is usually used.
+ * @return tag name
+ */
+ String tag();
+
+ /**
+ * Processes tasks of the worklet under the workflow context.
+ * @param context workflow context
+ * @throws WorkflowException workflow exception
+ */
+ void process(WorkflowContext context) throws WorkflowException;
+
+ /**
+ * Checks whether is this worklet next worklet to be done under the workflow context.
+ * @param context workflow context
+ * @return true means this worklet is the next worklet to be processed
+ * @throws WorkflowException workflow exception
+ */
+ boolean isNext(WorkflowContext context) throws WorkflowException;
+
+ /**
+ * Checks whether is this worklet completed or not. 'isCompleted' checking is triggered by an event task.
+ * @param context workflow context
+ * @param event an event triggering this 'isCompleted' checking
+ * @return completed or not
+ * @throws WorkflowException workflow exception
+ */
+ boolean isCompleted(WorkflowContext context, Event event) throws WorkflowException;
+
+ /**
+ * Completion event timeout handler.
+ * @param context workflow context
+ * @throws WorkflowException workflow exception
+ */
+ void timeout(WorkflowContext context) throws WorkflowException;
+
+ /**
+ * Common worklet enum.
+ */
+ enum Common implements Worklet {
+
+ /**
+ * Init worklet.
+ */
+ INIT {
+ @Override
+ public String tag() {
+ return INIT.name();
+ }
+
+ @Override
+ public void process(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").process should not be called");
+ }
+
+ @Override
+ public boolean isNext(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isNext should not be called");
+ }
+
+ @Override
+ public boolean isCompleted(WorkflowContext context, Event event)throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isCompleted should not be called");
+ }
+
+ @Override
+ public void timeout(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").timeout should not be called");
+ }
+ },
+
+ /**
+ * Completed worklet.
+ */
+ COMPLETED {
+ @Override
+ public String tag() {
+ return COMPLETED.name();
+ }
+
+ @Override
+ public void process(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").process should not be called");
+ }
+
+ @Override
+ public boolean isNext(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isNext should not be called");
+ }
+
+ @Override
+ public boolean isCompleted(WorkflowContext context, Event event)throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isCompleted should not be called");
+ }
+
+ @Override
+ public void timeout(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").timeout should not be called");
+ }
+ },
+
+ /**
+ * Interrupted worklet.
+ */
+ INTERRUPTED {
+ @Override
+ public String tag() {
+ return INTERRUPTED.name();
+ }
+
+ @Override
+ public void process(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").process should not be called");
+ }
+
+ @Override
+ public boolean isNext(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isNext should not be called");
+ }
+
+ @Override
+ public boolean isCompleted(WorkflowContext context, Event event)throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").isCompleted should not be called");
+ }
+
+ @Override
+ public void timeout(WorkflowContext context) throws WorkflowException {
+ throw new WorkflowException("(" + tag() + ").timeout should not be called");
+ }
+ }
+ }
+}
+
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workplace.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workplace.java
new file mode 100644
index 0000000..a7439d6
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workplace.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018-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.Collection;
+
+/**
+ * Abstract class for workplace. A common workflow data container for multiple work-flows.
+ */
+public abstract class Workplace extends WorkflowData {
+
+ public static final String SYSTEM_WORKPLACE = "system-workplace";
+
+ /**
+ * Constructor of workplace.
+ * @param data data model tree
+ */
+ public Workplace(DataModelTree data) {
+ super(data);
+ }
+
+ /**
+ * Gets workflow contexts of workplace.
+ * @return collection of workflow context
+ * @throws WorkflowException workflow exception
+ */
+ abstract Collection<WorkflowContext> getContexts() throws WorkflowException;
+
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceDescription.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceDescription.java
new file mode 100644
index 0000000..16515eb
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceDescription.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
+import java.util.Optional;
+
+/**
+ * Interface for workplace description.
+ */
+public interface WorkplaceDescription {
+
+ /**
+ * Workplace name field name.
+ */
+ String WP_NAME = "name";
+
+ /**
+ * Workplace data field name.
+ */
+ String WP_DATA = "data";
+
+ /**
+ * Gets workplace name.
+ * @return workplace name
+ */
+ String name();
+
+ /**
+ * Gets optional workplace data model.
+ * @return workplace optData model
+ */
+ Optional<JsonNode> data();
+
+ /**
+ * Gets json of workflow description.
+ * @return json of workflow description
+ */
+ JsonNode toJson();
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceStore.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceStore.java
new file mode 100644
index 0000000..b73cd4f
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceStore.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2018-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 org.onosproject.store.Store;
+import org.onosproject.store.service.StorageException;
+
+import java.util.Collection;
+
+/**
+ * Interface for workplace store.
+ */
+public interface WorkplaceStore extends Store<WorkflowDataEvent, WorkplaceStoreDelegate> {
+
+ /**
+ * Registers workplace on workplace store.
+ * @param name workplace name to register
+ * @param workplace workplace
+ * @throws StorageException storage exception
+ */
+ void registerWorkplace(String name, Workplace workplace) throws StorageException;
+
+ /**
+ * Removes workplace from workplace store.
+ * @param name workplace name to remove
+ * @throws StorageException storage exception
+ */
+ void removeWorkplace(String name) throws StorageException;
+
+ /**
+ * Gets workplace on workplace store.
+ * @param name workplace name to get
+ * @return workplace
+ * @throws StorageException storage exception
+ */
+ Workplace getWorkplace(String name) throws StorageException;
+
+ /**
+ * Commits workplace on workplace store.
+ * @param name workplace name to commit
+ * @param workplace workplace to commit
+ * @param handleEvent whether or not to handle workplace(workflow data) event
+ * @throws StorageException storage exception
+ */
+ void commitWorkplace(String name, Workplace workplace, boolean handleEvent) throws StorageException;
+
+ /**
+ * Gets all workplaces from workplace store.
+ * @return collection of workplace
+ * @throws StorageException storage exception
+ */
+ Collection<Workplace> getWorkplaces() throws StorageException;
+
+ /**
+ * Registers workflow context on workplace store.
+ * @param name workflow context name to register
+ * @param context workflow context to register
+ * @throws StorageException storage exception
+ */
+ void registerContext(String name, WorkflowContext context) throws StorageException;
+
+ /**
+ * Removes workflow context from workplace store.
+ * @param name workflow context name
+ * @throws StorageException storage exception
+ */
+ void removeContext(String name) throws StorageException;
+
+ /**
+ * Gets workflow context with name.
+ * @param name workflow context name to get
+ * @return workflow context
+ * @throws StorageException storage exception
+ */
+ WorkflowContext getContext(String name) throws StorageException;
+
+ /**
+ * Commits workflow context on workplace store.
+ * @param name workflow context name to commit
+ * @param context workflow context to commit
+ * @param handleEvent whether or not to handle workflow context(workflow data) event
+ * @throws StorageException storage exception
+ */
+ void commitContext(String name, WorkflowContext context, boolean handleEvent) throws StorageException;
+
+ /**
+ * Gets all workflow context from workplace store.
+ * @return collection of workflow context
+ * @throws StorageException storage exception
+ */
+ Collection<WorkflowContext> getContexts() throws StorageException;
+
+ /**
+ * Gets workflow contexts belonging to a workplace.
+ * @param workplaceName workplace name
+ * @return collection of workflow contexts belonging to a workplace
+ */
+ Collection<WorkflowContext> getWorkplaceContexts(String workplaceName);
+
+ /**
+ * Removes all workflow contexts beloinging to a workplace.
+ * @param workplaceName workplace name
+ */
+ void removeWorkplaceContexts(String workplaceName);
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceStoreDelegate.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceStoreDelegate.java
new file mode 100644
index 0000000..9e7ba14
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/WorkplaceStoreDelegate.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2018-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 org.onosproject.store.StoreDelegate;
+
+/**
+ * Workplace store delegate.
+ */
+public interface WorkplaceStoreDelegate extends StoreDelegate<WorkflowDataEvent> {
+}
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/package-info.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/package-info.java
new file mode 100644
index 0000000..7e68f8f
--- /dev/null
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-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 for workflow APIs.
+ */
+package org.onosproject.workflow.api;
\ No newline at end of file