diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 18e35c6744..6bb3917652 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -247,7 +247,7 @@ spring:
     database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.HSQLDialect}"
   datasource:
     driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.hsqldb.jdbc.JDBCDriver}"
-    url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false}"
+    url: "${SPRING_DATASOURCE_URL:jdbc:hsqldb:file:${SQL_DATA_FOLDER:/tmp}/thingsboardDb;sql.enforce_size=false;hsqldb.log_size=5}"
     username: "${SPRING_DATASOURCE_USERNAME:sa}"
     password: "${SPRING_DATASOURCE_PASSWORD:}"
 
diff --git a/dao/pom.xml b/dao/pom.xml
index d9463e4f9c..8d43822342 100644
--- a/dao/pom.xml
+++ b/dao/pom.xml
@@ -23,7 +23,6 @@
         1.4.0-SNAPSHOT
         thingsboard
     
-    org.thingsboard
     dao
     jar
 
diff --git a/pom.xml b/pom.xml
index 4b77abbd98..27e5216897 100755
--- a/pom.xml
+++ b/pom.xml
@@ -85,6 +85,7 @@
         extensions-api
         extensions-core
         extensions
+        rule-engine
         transport
         ui
         tools
diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml
new file mode 100644
index 0000000000..e23f8714e3
--- /dev/null
+++ b/rule-engine/pom.xml
@@ -0,0 +1,42 @@
+
+
+    4.0.0
+    
+        org.thingsboard
+        1.4.0-SNAPSHOT
+        thingsboard
+    
+    org.thingsboard
+    rule-engine
+    pom
+
+    Thingsboard Extensions
+    https://thingsboard.io
+
+    
+        ${basedir}/..
+    
+
+    
+        rule-engine-api
+        rule-engine-components
+    
+
+
diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml
new file mode 100644
index 0000000000..69cbc65965
--- /dev/null
+++ b/rule-engine/rule-engine-api/pom.xml
@@ -0,0 +1,67 @@
+
+
+
+    4.0.0
+    
+        org.thingsboard
+        1.4.0-SNAPSHOT
+        rule-engine
+    
+    org.thingsboard.rule-engine
+    rule-engine-api
+    jar
+
+    Thingsboard Rule Engine API
+    https://thingsboard.io
+
+    
+        UTF-8
+        ${basedir}/../..
+    
+
+    
+        
+            org.thingsboard.common
+            message
+            provided
+        
+        
+            org.thingsboard
+            extensions-api
+            provided
+        
+        
+            org.thingsboard
+            dao
+            provided
+        
+        
+            ch.qos.logback
+            logback-core
+            provided
+        
+        
+            ch.qos.logback
+            logback-classic
+            provided
+        
+    
+
\ No newline at end of file
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
new file mode 100644
index 0000000000..b833a97759
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
@@ -0,0 +1,29 @@
+package org.thingsboard.rule.engine.api;
+
+import org.thingsboard.server.common.msg.cluster.ServerAddress;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.UUID;
+
+/**
+ * Created by ashvayka on 13.01.18.
+ */
+public interface TbContext {
+
+    void tellNext(TbMsg msg);
+
+    void tellNext(TbMsg msg, String relationType);
+
+    void tellSelf(TbMsg msg, long delayMs);
+
+    void tellOthers(TbMsg msg);
+
+    void tellSibling(TbMsg msg, ServerAddress address);
+
+    void spawn(TbMsg msg);
+
+    void ack(UUID msg);
+
+    AttributesService getAttributesService();
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsg.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsg.java
new file mode 100644
index 0000000000..9917c6a505
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsg.java
@@ -0,0 +1,22 @@
+package org.thingsboard.rule.engine.api;
+
+import lombok.Data;
+import org.thingsboard.server.common.data.id.EntityId;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Created by ashvayka on 13.01.18.
+ */
+@Data
+public final class TbMsg implements Serializable {
+
+    private final UUID id;
+    private final String type;
+    private final EntityId originator;
+    private final TbMsgMetaData metaData;
+
+    private final byte[] data;
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsgMetaData.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsgMetaData.java
new file mode 100644
index 0000000000..56abf2a12d
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbMsgMetaData.java
@@ -0,0 +1,24 @@
+package org.thingsboard.rule.engine.api;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Created by ashvayka on 13.01.18.
+ */
+@Data
+public final class TbMsgMetaData implements Serializable {
+
+    private Map data;
+
+    public String getValue(String key) {
+        return data.get(key);
+    }
+
+    public void putValue(String key, String value) {
+        data.put(key, value);
+    }
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java
new file mode 100644
index 0000000000..70993df47a
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java
@@ -0,0 +1,16 @@
+package org.thingsboard.rule.engine.api;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public interface TbNode {
+
+    void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException;
+
+    void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException;
+
+    void destroy();
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java
new file mode 100644
index 0000000000..4ab84aaeed
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java
@@ -0,0 +1,14 @@
+package org.thingsboard.rule.engine.api;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Data
+public class TbNodeConfiguration {
+
+    private JsonNode data;
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java
new file mode 100644
index 0000000000..5a3744b08c
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java
@@ -0,0 +1,14 @@
+package org.thingsboard.rule.engine.api;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public class TbNodeException extends Exception {
+
+    public TbNodeException(Exception e) {
+        super(e);
+    }
+
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java
new file mode 100644
index 0000000000..15f4c30774
--- /dev/null
+++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java
@@ -0,0 +1,7 @@
+package org.thingsboard.rule.engine.api;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public class TbNodeState {
+}
diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml
new file mode 100644
index 0000000000..ee0d83f9a7
--- /dev/null
+++ b/rule-engine/rule-engine-components/pom.xml
@@ -0,0 +1,67 @@
+
+
+
+    4.0.0
+    
+        org.thingsboard
+        1.4.0-SNAPSHOT
+        rule-engine
+    
+    org.thingsboard.rule-engine
+    rule-engine-components
+    jar
+
+    Thingsboard Rule Engine Components
+    https://thingsboard.io
+
+    
+        UTF-8
+        ${basedir}/../..
+    
+
+    
+        
+            org.thingsboard
+            dao
+            provided
+        
+        
+            ch.qos.logback
+            logback-core
+            provided
+        
+        
+            ch.qos.logback
+            logback-classic
+            provided
+        
+        
+            org.thingsboard
+            extensions-api
+            provided
+        
+        
+            org.thingsboard.rule-engine
+            rule-engine-api
+            1.4.0-SNAPSHOT
+        
+    
+
\ No newline at end of file
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/TbNodeUtils.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/TbNodeUtils.java
new file mode 100644
index 0000000000..962ea10c9c
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/TbNodeUtils.java
@@ -0,0 +1,23 @@
+package org.thingsboard.rule.engine;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.thingsboard.rule.engine.api.TbNodeConfiguration;
+import org.thingsboard.rule.engine.api.TbNodeException;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public class TbNodeUtils {
+
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    public static  T convert(TbNodeConfiguration configuration, Class clazz) throws TbNodeException {
+        try {
+            return mapper.treeToValue(configuration.getData(), clazz);
+        } catch (JsonProcessingException e) {
+            throw new TbNodeException(e);
+        }
+    }
+
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
new file mode 100644
index 0000000000..034ee48e58
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
@@ -0,0 +1,35 @@
+package org.thingsboard.rule.engine.filter;
+
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.rule.engine.TbNodeUtils;
+import org.thingsboard.rule.engine.api.*;
+import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Slf4j
+public class TbMsgTypeFilterNode implements TbNode {
+
+    TbMsgTypeFilterNodeConfiguration config;
+
+    @Override
+    public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
+        this.config = TbNodeUtils.convert(configuration, TbMsgTypeFilterNodeConfiguration.class);
+    }
+
+    @Override
+    public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
+        ctx.tellNext(msg, Boolean.toString(config.getMessageTypes().contains(msg.getType())));
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java
new file mode 100644
index 0000000000..e7662070c4
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java
@@ -0,0 +1,15 @@
+package org.thingsboard.rule.engine.filter;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Data
+public class TbMsgTypeFilterNodeConfiguration {
+
+    private List messageTypes;
+
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
new file mode 100644
index 0000000000..b623af7609
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
@@ -0,0 +1,51 @@
+package org.thingsboard.rule.engine.metadata;
+
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.rule.engine.TbNodeUtils;
+import org.thingsboard.rule.engine.api.*;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Slf4j
+public class TbGetAttributesNode implements TbNode {
+
+    TbGetAttributesNodeConfiguration config;
+
+    @Override
+    public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
+        this.config = TbNodeUtils.convert(configuration, TbGetAttributesNodeConfiguration.class);
+    }
+
+    @Override
+    public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
+        try {
+            //TODO: refactor this to work async and fetch attributes from cache.
+            AttributesService service = ctx.getAttributesService();
+            fetchAttributes(msg, service, config.getClientAttributeNames(), DataConstants.CLIENT_SCOPE, "cs.");
+            fetchAttributes(msg, service, config.getServerAttributeNames(), DataConstants.SERVER_SCOPE, "ss.");
+            fetchAttributes(msg, service, config.getSharedAttributeNames(), DataConstants.SHARED_SCOPE, "shared.");
+            ctx.tellNext(msg);
+        } catch (Exception e) {
+            log.warn("[{}][{}] Failed to fetch attributes", msg.getOriginator(), msg.getId(), e);
+            throw new TbNodeException(e);
+        }
+    }
+
+    private void fetchAttributes(TbMsg msg, AttributesService service, List attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException {
+        if (attributeNames != null && attributeNames.isEmpty()) {
+            List attributes = service.find(msg.getOriginator(), scope, attributeNames).get();
+            attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString()));
+        }
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java
new file mode 100644
index 0000000000..076500c7ec
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java
@@ -0,0 +1,17 @@
+package org.thingsboard.rule.engine.metadata;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Data
+public class TbGetAttributesNodeConfiguration {
+
+    private List clientAttributeNames;
+    private List sharedAttributeNames;
+    private List serverAttributeNames;
+
+}
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNode.java
new file mode 100644
index 0000000000..837f33342f
--- /dev/null
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNode.java
@@ -0,0 +1,52 @@
+package org.thingsboard.rule.engine.transform;
+
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.rule.engine.TbNodeUtils;
+import org.thingsboard.rule.engine.api.*;
+import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
+import org.thingsboard.server.dao.attributes.AttributesService;
+
+import java.util.List;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+@Slf4j
+public class TbTransformNode implements TbNode {
+
+    TbGetAttributesNodeConfiguration config;
+
+    @Override
+    public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException {
+        this.config = TbNodeUtils.convert(configuration, TbGetAttributesNodeConfiguration.class);
+    }
+
+    @Override
+    public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
+        try {
+            //TODO: refactor this to work async and fetch attributes from cache.
+            AttributesService service = ctx.getAttributesService();
+            fetchAttributes(msg, service, config.getClientAttributeNames(), DataConstants.CLIENT_SCOPE, "cs.");
+            fetchAttributes(msg, service, config.getServerAttributeNames(), DataConstants.SERVER_SCOPE, "ss.");
+            fetchAttributes(msg, service, config.getSharedAttributeNames(), DataConstants.SHARED_SCOPE, "shared.");
+            ctx.tellNext(msg);
+        } catch (Exception e) {
+            log.warn("[{}][{}] Failed to fetch attributes", msg.getOriginator(), msg.getId(), e);
+            throw new TbNodeException(e);
+        }
+    }
+
+    private void fetchAttributes(TbMsg msg, AttributesService service, List attributeNames, String scope, String prefix) throws InterruptedException, java.util.concurrent.ExecutionException {
+        if (attributeNames != null && attributeNames.isEmpty()) {
+            List attributes = service.find(msg.getOriginator(), scope, attributeNames).get();
+            attributes.forEach(attr -> msg.getMetaData().putValue(prefix + attr.getKey(), attr.getValueAsString()));
+        }
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}