[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