You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by an...@apache.org on 2016/03/28 10:47:48 UTC

[08/50] [abbrv] ignite git commit: IGNITE-2597 Refactored to websockets.

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-agent/src/main/java/org/apache/ignite/console/demo/AgentSqlDemo.java
----------------------------------------------------------------------
diff --git a/modules/control-center-agent/src/main/java/org/apache/ignite/console/demo/AgentSqlDemo.java b/modules/control-center-agent/src/main/java/org/apache/ignite/console/demo/AgentSqlDemo.java
index a471d25..28c9a69 100644
--- a/modules/control-center-agent/src/main/java/org/apache/ignite/console/demo/AgentSqlDemo.java
+++ b/modules/control-center-agent/src/main/java/org/apache/ignite/console/demo/AgentSqlDemo.java
@@ -33,21 +33,22 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.QueryIndexType;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.console.agent.AgentConfiguration;
 import org.apache.ignite.console.demo.model.Car;
 import org.apache.ignite.console.demo.model.Country;
 import org.apache.ignite.console.demo.model.Department;
 import org.apache.ignite.console.demo.model.Employee;
 import org.apache.ignite.console.demo.model.Parking;
-import org.apache.ignite.cache.QueryEntity;
-import org.apache.ignite.cache.QueryIndex;
-import org.apache.ignite.cache.QueryIndexType;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.logger.log4j.Log4JLogger;
 import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinderAdapter;
 import org.apache.log4j.Logger;
@@ -64,7 +65,7 @@ import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_JETTY_PO
  */
 public class AgentSqlDemo {
     /** */
-    private static final Logger log = Logger.getLogger(AgentMetadataDemo.class.getName());
+    private static final Logger log = Logger.getLogger(AgentSqlDemo.class.getName());
 
     /** */
     private static final AtomicBoolean initLatch = new AtomicBoolean();
@@ -108,12 +109,12 @@ public class AgentSqlDemo {
         CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(COUNTRY_CACHE_NAME);
 
         // Configure cacheCountry types.
-        Collection<QueryEntity> queryEntities = new ArrayList<>();
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
 
         // COUNTRY.
         QueryEntity type = new QueryEntity();
 
-        queryEntities.add(type);
+        qryEntities.add(type);
 
         type.setKeyType(Integer.class.getName());
         type.setValueType(Country.class.getName());
@@ -130,7 +131,7 @@ public class AgentSqlDemo {
         // Indexes for COUNTRY.
         type.setIndexes(Collections.singletonList(new QueryIndex("id", QueryIndexType.SORTED, false, "PRIMARY_KEY_6")));
 
-        ccfg.setQueryEntities(queryEntities);
+        ccfg.setQueryEntities(qryEntities);
 
         return ccfg;
     }
@@ -142,12 +143,12 @@ public class AgentSqlDemo {
         CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(DEPARTMENT_CACHE_NAME);
 
         // Configure cacheDepartment types.
-        Collection<QueryEntity> queryEntities = new ArrayList<>();
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
 
         // DEPARTMENT.
         QueryEntity type = new QueryEntity();
 
-        queryEntities.add(type);
+        qryEntities.add(type);
 
         type.setKeyType(Integer.class.getName());
         type.setValueType(Department.class.getName());
@@ -164,7 +165,7 @@ public class AgentSqlDemo {
         // Indexes for DEPARTMENT.
         type.setIndexes(Collections.singletonList(new QueryIndex("id", QueryIndexType.SORTED, false, "PRIMARY_KEY_4")));
 
-        ccfg.setQueryEntities(queryEntities);
+        ccfg.setQueryEntities(qryEntities);
 
         return ccfg;
     }
@@ -176,12 +177,12 @@ public class AgentSqlDemo {
         CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(EMPLOYEE_CACHE_NAME);
 
         // Configure cacheEmployee types.
-        Collection<QueryEntity> queryEntities = new ArrayList<>();
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
 
         // EMPLOYEE.
         QueryEntity type = new QueryEntity();
 
-        queryEntities.add(type);
+        qryEntities.add(type);
 
         type.setKeyType(Integer.class.getName());
         type.setValueType(Employee.class.getName());
@@ -207,23 +208,23 @@ public class AgentSqlDemo {
 
         indexes.add(new QueryIndex("id", QueryIndexType.SORTED, false, "PRIMARY_KEY_7"));
 
-        QueryIndex index = new QueryIndex();
+        QueryIndex idx = new QueryIndex();
 
-        index.setName("EMP_NAMES");
-        index.setIndexType(QueryIndexType.SORTED);
+        idx.setName("EMP_NAMES");
+        idx.setIndexType(QueryIndexType.SORTED);
         LinkedHashMap<String, Boolean> indFlds = new LinkedHashMap<>();
 
-        indFlds.put("firstName", false);
-        indFlds.put("lastName", false);
+        indFlds.put("firstName", Boolean.FALSE);
+        indFlds.put("lastName", Boolean.FALSE);
 
-        index.setFields(indFlds);
+        idx.setFields(indFlds);
 
-        indexes.add(index);
+        indexes.add(idx);
         indexes.add(new QueryIndex("salary", QueryIndexType.SORTED, false, "EMP_SALARY"));
 
         type.setIndexes(indexes);
 
-        ccfg.setQueryEntities(queryEntities);
+        ccfg.setQueryEntities(qryEntities);
 
         return ccfg;
     }
@@ -235,12 +236,12 @@ public class AgentSqlDemo {
         CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(PARKING_CACHE_NAME);
 
         // Configure cacheParking types.
-        Collection<QueryEntity> queryEntities = new ArrayList<>();
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
 
         // PARKING.
         QueryEntity type = new QueryEntity();
 
-        queryEntities.add(type);
+        qryEntities.add(type);
 
         type.setKeyType(Integer.class.getName());
         type.setValueType(Parking.class.getName());
@@ -250,14 +251,14 @@ public class AgentSqlDemo {
 
         qryFlds.put("id", "java.lang.Integer");
         qryFlds.put("name", "java.lang.String");
-        qryFlds.put("capacity", "java.lang.Integer");;
+        qryFlds.put("capacity", "java.lang.Integer");
 
         type.setFields(qryFlds);
 
         // Indexes for PARKING.
         type.setIndexes(Collections.singletonList(new QueryIndex("id", QueryIndexType.SORTED, false, "PRIMARY_KEY_F")));
 
-        ccfg.setQueryEntities(queryEntities);
+        ccfg.setQueryEntities(qryEntities);
 
         return ccfg;
     }
@@ -269,12 +270,12 @@ public class AgentSqlDemo {
         CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(CAR_CACHE_NAME);
 
         // Configure cacheCar types.
-        Collection<QueryEntity> queryEntities = new ArrayList<>();
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
 
         // CAR.
         QueryEntity type = new QueryEntity();
 
-        queryEntities.add(type);
+        qryEntities.add(type);
 
         type.setKeyType(Integer.class.getName());
         type.setValueType(Car.class.getName());
@@ -291,7 +292,7 @@ public class AgentSqlDemo {
         // Indexes for CAR.
         type.setIndexes(Collections.singletonList(new QueryIndex("id", QueryIndexType.SORTED, false, "PRIMARY_KEY_1")));
 
-        ccfg.setQueryEntities(queryEntities);
+        ccfg.setQueryEntities(qryEntities);
 
         return ccfg;
     }
@@ -305,13 +306,13 @@ public class AgentSqlDemo {
         if (places < 0)
             throw new IllegalArgumentException();
 
-        long factor = (long) Math.pow(10, places);
+        long factor = (long)Math.pow(10, places);
 
         val *= factor;
 
         long tmp = Math.round(val);
 
-        return (double) tmp / factor;
+        return (double)tmp / factor;
     }
 
     /**
@@ -319,7 +320,8 @@ public class AgentSqlDemo {
      * @param range Time range in milliseconds.
      */
     private static void populateCacheEmployee(Ignite ignite, long range) {
-        log.debug("DEMO: Start employees population with data...");
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Start employees population with data...");
 
         IgniteCache<Integer, Country> cacheCountry = ignite.cache(COUNTRY_CACHE_NAME);
 
@@ -346,18 +348,20 @@ public class AgentSqlDemo {
             double r = rnd.nextDouble();
 
             cacheEmployee.put(i, new Employee(i, depId, depId, "First name employee #" + n,
-                    "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
-                    new java.sql.Date((long)(r * range)), "Job employee #" + n, 500 + round(r * 2000, 2)));
+                "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
+                new java.sql.Date((long)(r * range)), "Job employee #" + n, 500 + round(r * 2000, 2)));
         }
 
-        log.debug("DEMO: Finished employees population.");
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Finished employees population.");
     }
 
     /**
      * @param ignite Ignite.
      */
     private static void populateCacheCar(Ignite ignite) {
-        log.debug("DEMO: Start cars population...");
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Start cars population...");
 
         IgniteCache<Integer, Parking> cacheParking = ignite.cache(PARKING_CACHE_NAME);
 
@@ -369,7 +373,8 @@ public class AgentSqlDemo {
         for (int i = 0, n = 1; i < CAR_CNT; i++, n++)
             cacheCar.put(i, new Car(i, rnd.nextInt(PARK_CNT), "Car #" + n));
 
-        log.debug("DEMO: Finished cars population.");
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Finished cars population.");
     }
 
     /**
@@ -390,7 +395,7 @@ public class AgentSqlDemo {
             }
         });
 
-        ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) srvc;
+        ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor)srvc;
 
         // Setting up shutdown policy.
         executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
@@ -428,8 +433,8 @@ public class AgentSqlDemo {
                             double r = rnd.nextDouble();
 
                             cacheEmployee.put(id, new Employee(id, depId, depId, "First name employee #" + n,
-                                    "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
-                                    new java.sql.Date((long)(r * diff)), "Job employee #" + n, 500 + round(r * 2000, 2)));
+                                "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
+                                new java.sql.Date((long)(r * diff)), "Job employee #" + n, 500 + round(r * 2000, 2)));
 
                             if (rnd.nextBoolean())
                                 cacheEmployee.remove(rnd.nextInt(EMPL_CNT));
@@ -515,17 +520,27 @@ public class AgentSqlDemo {
 
                 cfg.setDiscoverySpi(discoSpi);
 
+                TcpCommunicationSpi commSpi = new TcpCommunicationSpi();
+
+                commSpi.setSharedMemoryPort(-1);
+
+                cfg.setCommunicationSpi(commSpi);
+
                 cfg.setCacheConfiguration(cacheCountry(), cacheDepartment(), cacheEmployee(), cacheParking(), cacheCar());
 
+                cfg.getConnectorConfiguration().setPort(60700);
+
                 System.setProperty(IGNITE_JETTY_PORT, "60800");
                 System.setProperty(IGNITE_NO_ASCII, "true");
 
-                log.debug("DEMO: Start embedded node with indexed enabled caches...");
+                if (log.isDebugEnabled())
+                    log.debug("DEMO: Start embedded node with indexed enabled caches...");
 
                 IgniteEx ignite = (IgniteEx)Ignition.start(cfg);
 
-                String host = ((Collection<String>)
-                    ignite.localNode().attribute(ATTR_REST_JETTY_ADDRS)).iterator().next();
+                Collection<String> jettyAddrs = ignite.localNode().attribute(ATTR_REST_JETTY_ADDRS);
+
+                String host = jettyAddrs == null ? null : jettyAddrs.iterator().next();
 
                 Integer port = ignite.localNode().attribute(ATTR_REST_JETTY_PORT);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/.eslintrc
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/.eslintrc b/modules/control-center-web/src/main/js/.eslintrc
index 6d2b466..3e543f4 100644
--- a/modules/control-center-web/src/main/js/.eslintrc
+++ b/modules/control-center-web/src/main/js/.eslintrc
@@ -20,6 +20,7 @@ ecmaFeatures:
 
 globals:
     _: true
+    io: true
     window: true
     global: true
     angular: true

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/.gitignore
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/.gitignore b/modules/control-center-web/src/main/js/.gitignore
index 05d5693..bb977f8 100644
--- a/modules/control-center-web/src/main/js/.gitignore
+++ b/modules/control-center-web/src/main/js/.gitignore
@@ -5,4 +5,7 @@ jspm_packages
 .npmrc
 build
 app/plugins
-public/stylesheets/*.css
\ No newline at end of file
+public/stylesheets/*.css
+serve/config/*.json
+serve/agent_dists/*.zip
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/data/colors.json
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/data/colors.json b/modules/control-center-web/src/main/js/app/data/colors.json
new file mode 100644
index 0000000..188e485
--- /dev/null
+++ b/modules/control-center-web/src/main/js/app/data/colors.json
@@ -0,0 +1,22 @@
+[
+  "#1f77b4",
+  "#ff7f0e",
+  "#2ca02c",
+  "#d62728",
+  "#9467bd",
+  "#8c564b",
+  "#e377c2",
+  "#7f7f7f",
+  "#bcbd22",
+  "#17becf",
+  "#ffbb78",
+  "#98df8a",
+  "#ff9896",
+  "#c5b0d5",
+  "#aec7e8",
+  "#c49c94",
+  "#f7b6d2",
+  "#c7c7c7",
+  "#dbdb8d",
+  "#9edae5"
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/decorator/select.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/decorator/select.js b/modules/control-center-web/src/main/js/app/decorator/select.js
index f770fc1..f232f88 100644
--- a/modules/control-center-web/src/main/js/app/decorator/select.js
+++ b/modules/control-center-web/src/main/js/app/decorator/select.js
@@ -17,45 +17,54 @@
 
 import angular from 'angular';
 
+/**
+ * Special decorator that fix problem in AngularStrap selectAll / deselectAll methods.
+ * If this problem will be fixed in AngularStrap we can remove this delegate.
+ */
 angular.module('mgcrea.ngStrap.select')
     .decorator('$select', ($delegate) => {
         function SelectFactoryDecorated(element, controller, config) {
             const deligate = $delegate(element, controller, config);
 
-            const scope = deligate.$scope;
+            // Common vars.
+            const options = angular.extend({}, $delegate.defaults, config);
 
-            const $selectAllDeligate = scope.$selectAll;
+            const scope = deligate.$scope;
 
-            scope.$selectAll = () => {
-                if (scope.$isMultiple) {
-                    const newActiveIndex = [];
+            const selectAll = (active) => {
+                var selected = [];
 
-                    for (let i = 0; i < scope.$matches.length; i++)
-                        newActiveIndex.push(i);
+                scope.$apply(function () {
+                    for (var i = 0; i < scope.$matches.length; i++) {
+                        if (scope.$isActive(i) === active) {
+                            selected[i] = scope.$matches[i].value;
 
-                    scope.$activeIndex = newActiveIndex;
+                            deligate.activate(i);
 
-                    controller.$setViewValue(scope.$activeIndex.map((index) => {
-                        if (angular.isUndefined(scope.$matches[index]))
-                            return null;
+                            controller.$setViewValue(scope.$activeIndex.map(function (index) {
+                                if (angular.isUndefined(scope.$matches[index])) {
+                                    return null;
+                                }
+                                return scope.$matches[index].value;
+                            }));
+                        }
+                    }
+                });
 
-                        return scope.$matches[index].value;
-                    }));
+                // Emit events.
+                for (var i = 0; i < selected.length; i++) {
+                    if (selected[i]) {
+                        scope.$emit(options.prefixEvent + '.select', selected[i], i, deligate);
+                    }
                 }
-                else
-                    $selectAllDeligate();
             };
 
-            const $selectNoneDeligate = scope.$selectNone;
+            scope.$selectAll = () => {
+                scope.$$postDigest(selectAll.bind(this, false));
+            };
 
             scope.$selectNone = () => {
-                if (scope.$isMultiple) {
-                    scope.$activeIndex = [];
-
-                    controller.$setViewValue([]);
-                }
-                else
-                    $selectNoneDeligate();
+                scope.$$postDigest(selectAll.bind(this, true));
             };
 
             return deligate;

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/index.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/index.js b/modules/control-center-web/src/main/js/app/index.js
index a807a3c..ad92c86 100644
--- a/modules/control-center-web/src/main/js/app/index.js
+++ b/modules/control-center-web/src/main/js/app/index.js
@@ -20,26 +20,26 @@ import _ from 'lodash';
 import ace from 'ace';
 import angular from 'angular';
 import pdfMake from 'pdfmake';
+import io from 'socket.io-client';
 
 window._ = _;
-window.jQuery = jQuery;
 window.ace = ace;
 window.require = ace.require; // TODO Should be removed after full refactoring to directives.
-window.angular = angular;
 window.pdfMake = pdfMake;
 
-import 'angular-ui-router';
-import 'angular-ui-router-metatags';
 import 'angular-animate';
 import 'angular-sanitize';
-import 'angular-ui-grid';
+import 'angular-strap';
+import 'angular-socket-io';
 import 'angular-loading';
+import 'angular-retina';
+import 'angular-ui-router';
+import 'angular-ui-router-metatags';
+import 'angular-smart-table';
+import 'angular-ui-grid';
 import 'angular-drag-and-drop-lists';
 import 'angular-nvd3';
-import 'angular-retina';
-import 'angular-strap';
 import 'angular-tree-control';
-import 'angular-smart-table';
 
 import 'bootstrap-carousel';
 import 'file-saver';
@@ -55,7 +55,7 @@ import 'angular-ui-grid/ui-grid.css!';
 import 'angular-loading/angular-loading.css!';
 import 'angular-motion/dist/angular-motion.css!';
 
-// import './decorator/select';
+import './decorator/select';
 
 import './modules/form/form.module';
 import './modules/JavaTypes/JavaTypes.provider';
@@ -94,10 +94,12 @@ import igniteFormFieldJavaClass from './directives/form-field-java-class/form-fi
 import igniteBsAffixUpdate from './directives/bs-affix-update.directive';
 
 // Services.
-import cleanup from './services/cleanup/cleanup.service';
+import cleanup from './services/cleanup.service';
 import GeneratorXml from './services/Generator/Xml.service';
 import GeneratorJava from './services/Generator/Java.service';
-import IgniteCountries from './services/Countries/Countries.service';
+import IgniteCountries from './services/Countries.service';
+import IgniteChartColors from './services/ChartColors.service';
+import IgniteAgentMonitor from './services/AgentMonitor.service';
 
 // Providers
 
@@ -107,9 +109,13 @@ import byName from './filters/byName.filter';
 
 angular
 .module('ignite-console', [
+    'ngRetina',
+    'btford.socket-io',
+    'ngAnimate',
+    'ngSanitize',
+    'mgcrea.ngStrap',
     'ui.router',
     'ui.router.metatags',
-    'ngRetina',
     // Base modules.
     'ignite-console.user',
     'ignite-console.branding',
@@ -149,6 +155,8 @@ angular
 .service(...GeneratorXml)
 .service(...GeneratorJava)
 .service(...IgniteCountries)
+.service(...IgniteChartColors)
+.service(...IgniteAgentMonitor)
 // Providers.
 // Filters.
 .filter(...hasPojo)
@@ -179,14 +187,15 @@ angular
 .run(['$rootScope', ($root) => {
     $root._ = _;
 }])
-.run(['$rootScope', '$state', 'MetaTags', 'Auth', 'User', ($root, $state, $meta, Auth, User) => {
+.run(['$rootScope', '$state', 'MetaTags', 'Auth', 'User', 'IgniteAgentMonitor', ($root, $state, $meta, Auth, User, AgentMonitor) => {
     $root.$state = $state;
 
     $root.$meta = $meta;
 
     if (Auth.authorized) {
         User.read()
-            .then((user) => $root.$broadcast('user', user));
+            .then((user) => $root.$broadcast('user', user))
+            .then(() => AgentMonitor.init());
     }
 }])
 .run(['$rootScope', ($root) => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/services/AgentMonitor.service.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/services/AgentMonitor.service.js b/modules/control-center-web/src/main/js/app/services/AgentMonitor.service.js
new file mode 100644
index 0000000..cf66b61
--- /dev/null
+++ b/modules/control-center-web/src/main/js/app/services/AgentMonitor.service.js
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+class IgniteAgentMonitor {
+    constructor(socketFactory, $root, $q, $state, $modal, $common) {
+        this._scope = $root.$new();
+
+        $root.$on('$stateChangeStart', () => {
+            this.stopWatch();
+        });
+
+        // Pre-fetch modal dialogs.
+        this._downloadAgentModal = $modal({
+            scope: this._scope,
+            templateUrl: '/templates/agent-download.html',
+            show: false,
+            backdrop: 'static'
+        });
+
+        const _modalHide = this._downloadAgentModal.hide;
+
+        /**
+         * Special dialog hide function.
+         */
+        this._downloadAgentModal.hide = () => {
+            $common.hideAlert();
+
+            _modalHide();
+        };
+
+        /**
+         * Close dialog and go by specified link.
+         */
+        this._scope.back = () => {
+            $state.go(this._scope.backState);
+        };
+
+        this._scope.downloadAgent = () => {
+            const lnk = document.createElement('a');
+
+            lnk.setAttribute('href', '/api/v1/agent/download/zip');
+            lnk.setAttribute('target', '_self');
+            lnk.setAttribute('download', null);
+            lnk.style.display = 'none';
+
+            document.body.appendChild(lnk);
+
+            lnk.click();
+
+            document.body.removeChild(lnk);
+        };
+
+        this._scope.hasAgents = null;
+        this._scope.showModal = false;
+
+        /**
+         * @type {Socket}
+         */
+        this._socket = null;
+
+        this._socketFactory = socketFactory;
+
+        this._$q = $q;
+    }
+
+    /**
+     * @private
+     */
+    _checkModal() {
+        if (this._scope.showModal && !this._scope.hasAgents)
+            this._downloadAgentModal.$promise.then(this._downloadAgentModal.show);
+        else if ((this._scope.hasAgents || !this._scope.showModal) && this._downloadAgentModal.$isShown)
+            this._downloadAgentModal.hide();
+    }
+
+    /**
+     * @returns {Promise}
+     */
+    awaitAgent() {
+        if (this._scope.hasAgents)
+            return this._$q.when();
+
+        if (this._scope.hasAgents !== null)
+            this._checkModal();
+
+        const latch = this._$q.defer();
+
+        const offConnected = this._scope.$on('agent:connected', (event, success) => {
+            offConnected();
+
+            if (success)
+                return latch.resolve();
+
+            latch.reject();
+        });
+
+        return latch.promise;
+    }
+
+    init() {
+        this._socket = this._socketFactory();
+
+        this._socket.on('agent:count', ({count}) => {
+            this._scope.hasAgents = count > 0;
+
+            this._checkModal();
+
+            if (this._scope.hasAgents)
+                this._scope.$broadcast('agent:connected', true);
+        });
+
+        this._socket.on('disconnect', () => {
+            this._scope.hasAgents = false;
+
+            this._checkModal();
+        });
+    }
+
+    /**
+     * @param {Object} back
+     * @param {Function} startDemo
+     * @returns {Promise}
+     */
+    startWatch(back, startDemo) {
+        this._scope.backState = back.state;
+        this._scope.backText = back.text;
+
+        this._scope.agentGoal = back.goal;
+
+        this._scope.showModal = true;
+
+        this._scope.startDemo = startDemo;
+
+        return this.awaitAgent();
+    }
+
+    /**
+     *
+     * @param {String} event
+     * @param {Object} [args]
+     * @returns {Promise}
+     * @private
+     */
+    _emit(event, ...args) {
+        if (!this._socket)
+            return this._$q.reject('Failed to connect to agent');
+
+        const latch = this._$q.defer();
+
+        const onDisconnect = () => {
+            this._socket.removeListener('disconnect', onDisconnect);
+
+            latch.reject('Connection to server was closed');
+        };
+
+        this._socket.on('disconnect', onDisconnect);
+
+        args.push((err, res) => {
+            this._socket.removeListener('disconnect', onDisconnect);
+
+            if (err)
+                latch.reject(err);
+
+            latch.resolve(res);
+        });
+
+        this._socket.emit(event, ...args);
+
+        return latch.promise;
+    }
+
+    drivers() {
+        return this._emit('schemaImport:drivers');
+    }
+
+    /**
+     *
+     * @param {Object} preset
+     * @returns {Promise}
+     */
+    schemas(preset) {
+        return this._emit('schemaImport:schemas', preset);
+    }
+
+    /**
+     *
+     * @param {Object} preset
+     * @returns {Promise}
+     */
+    tables(preset) {
+        return this._emit('schemaImport:tables', preset);
+    }
+
+    /**
+     *
+     * @param {String} event
+     * @param {Object} [args]
+     * @returns {Promise}
+     * @private
+     */
+    _rest(event, ...args) {
+        return this._downloadAgentModal.$promise
+            .then(() => this._emit(event, ...args))
+            .then((res) => {
+                this._downloadAgentModal.hide();
+
+                return res;
+            })
+            .catch((errMsg) => {
+                this._downloadAgentModal.show();
+
+                return this._$q.reject(errMsg);
+            });
+    }
+
+    /**
+     * @param {Boolean} demo
+     * @param {Boolean} [attr]
+     * @param {Boolean} [mtr]
+     * @returns {Promise}
+     */
+    topology(demo, attr, mtr) {
+        return this._rest('node:topology', !!demo, !!attr, !!mtr);
+    }
+
+    /**
+     * @param {Object} args
+     * @returns {Promise}
+     */
+    queryClose(args) {
+        if (!args || !args.queryId)
+            return this._$q.when();
+
+        return this._rest('node:query:close', {demo: args.demo, cacheName: args.cacheName, queryId: args.queryId});
+    }
+
+    /**
+     * @param {Object} args
+     * @returns {Promise}
+     */
+    query(args) {
+        return this._rest('node:query', args);
+    }
+
+    /**
+     * @param {Boolean} demo
+     * @returns {Promise}
+     */
+    metadata(demo) {
+        return this._rest('node:cache:metadata', {demo});
+    }
+
+    /**
+     * @param {Object} args
+     * @returns {Promise}
+     */
+    next(args) {
+        return this._rest('node:query:fetch', args);
+    }
+
+    stopWatch() {
+        this._scope.showModal = false;
+
+        this._checkModal();
+
+        this._scope.$broadcast('agent:connected', false);
+    }
+}
+
+IgniteAgentMonitor.$inject = ['socketFactory', '$rootScope', '$q', '$state', '$modal', '$common'];
+
+export default ['IgniteAgentMonitor', IgniteAgentMonitor];

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/services/ChartColors.service.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/services/ChartColors.service.js b/modules/control-center-web/src/main/js/app/services/ChartColors.service.js
new file mode 100644
index 0000000..ec3f365
--- /dev/null
+++ b/modules/control-center-web/src/main/js/app/services/ChartColors.service.js
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import COLORS from 'app/data/colors.json!';
+
+export default ['IgniteChartColors', function() {
+    return COLORS;
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/services/Countries.service.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/services/Countries.service.js b/modules/control-center-web/src/main/js/app/services/Countries.service.js
new file mode 100644
index 0000000..82b8626
--- /dev/null
+++ b/modules/control-center-web/src/main/js/app/services/Countries.service.js
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+// Java built-in short class names.
+import COUNTRIES from 'app/data/countries.json!';
+
+export default ['IgniteCountries', function() {
+    return COUNTRIES;
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/services/Countries/Countries.service.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/services/Countries/Countries.service.js b/modules/control-center-web/src/main/js/app/services/Countries/Countries.service.js
deleted file mode 100644
index 82b8626..0000000
--- a/modules/control-center-web/src/main/js/app/services/Countries/Countries.service.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-// Java built-in short class names.
-import COUNTRIES from 'app/data/countries.json!';
-
-export default ['IgniteCountries', function() {
-    return COUNTRIES;
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/services/cleanup.service.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/services/cleanup.service.js b/modules/control-center-web/src/main/js/app/services/cleanup.service.js
new file mode 100644
index 0000000..c50bfe0
--- /dev/null
+++ b/modules/control-center-web/src/main/js/app/services/cleanup.service.js
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import angular from 'angular';
+
+const isArray = angular.isArray;
+const isDefined = angular.isDefined;
+const isNumber = angular.isNumber;
+const isObject = angular.isObject;
+const isString = angular.isString;
+const isUndefined = angular.isUndefined;
+const isBoolean = (val) => typeof val === 'boolean';
+
+export default ['$cleanup', () => {
+    const cleanup = (original, dist) => {
+        if (isUndefined(original))
+            return dist;
+
+        if (isObject(original)) {
+            let key;
+
+            for (key in original) {
+                if (original.hasOwnProperty(key)) {
+                    const attr = cleanup(original[key]);
+
+                    if (isDefined(attr)) {
+                        dist = dist || {};
+                        dist[key] = attr;
+                    }
+                }
+            }
+        } else if ((isString(original) && original.length) || isNumber(original) || isBoolean(original))
+            dist = original;
+        else if (isArray(original) && original.length) {
+            dist = [];
+
+            let i = 0;
+            const l = original.length;
+
+            for (; i < l; i++)
+                dist[i] = cleanup(original[i], {});
+        }
+
+        return dist;
+    };
+
+    return cleanup;
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/app/services/cleanup/cleanup.service.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/services/cleanup/cleanup.service.js b/modules/control-center-web/src/main/js/app/services/cleanup/cleanup.service.js
deleted file mode 100644
index c50bfe0..0000000
--- a/modules/control-center-web/src/main/js/app/services/cleanup/cleanup.service.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-import angular from 'angular';
-
-const isArray = angular.isArray;
-const isDefined = angular.isDefined;
-const isNumber = angular.isNumber;
-const isObject = angular.isObject;
-const isString = angular.isString;
-const isUndefined = angular.isUndefined;
-const isBoolean = (val) => typeof val === 'boolean';
-
-export default ['$cleanup', () => {
-    const cleanup = (original, dist) => {
-        if (isUndefined(original))
-            return dist;
-
-        if (isObject(original)) {
-            let key;
-
-            for (key in original) {
-                if (original.hasOwnProperty(key)) {
-                    const attr = cleanup(original[key]);
-
-                    if (isDefined(attr)) {
-                        dist = dist || {};
-                        dist[key] = attr;
-                    }
-                }
-            }
-        } else if ((isString(original) && original.length) || isNumber(original) || isBoolean(original))
-            dist = original;
-        else if (isArray(original) && original.length) {
-            dist = [];
-
-            let i = 0;
-            const l = original.length;
-
-            for (; i < l; i++)
-                dist[i] = cleanup(original[i], {});
-        }
-
-        return dist;
-    };
-
-    return cleanup;
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/config.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/config.js b/modules/control-center-web/src/main/js/config.js
index 406ce17..a54b40f 100644
--- a/modules/control-center-web/src/main/js/config.js
+++ b/modules/control-center-web/src/main/js/config.js
@@ -25,10 +25,11 @@ System.config({
     "angular-loading": "github:darthwade/angular-loading@0.1.4",
     "angular-motion": "github:mgcrea/angular-motion@0.4.3",
     "angular-nvd3": "github:krispo/angular-nvd3@1.0.5",
-    "angular-retina": "github:jrief/angular-retina@0.3.11",
+    "angular-retina": "github:jrief/angular-retina@0.3.8",
     "angular-sanitize": "github:angular/bower-angular-sanitize@1.5.1",
     "angular-smart-table": "github:lorenzofox3/Smart-Table@2.1.7",
-    "angular-strap": "github:akuznetsov-gridgain/angular-strap@fix-1852-2.3.6",
+    "angular-socket-io": "github:btford/angular-socket-io@0.7.0",
+    "angular-strap": "github:mgcrea/angular-strap@2.3.7",
     "angular-tree-control": "github:wix/angular-tree-control@0.2.23",
     "angular-ui-ace": "github:angular-ui/ui-ace@0.2.3",
     "angular-ui-grid": "github:angular-ui/bower-ui-grid@3.1.1",
@@ -54,14 +55,9 @@ System.config({
     "nvd3": "npm:nvd3@1.8.1",
     "pdfmake": "github:bpampuch/pdfmake@0.1.20",
     "query-command-supported": "github:zenorocha/document.queryCommandSupported@1.0.0",
+    "socket.io-client": "github:socketio/socket.io-client@1.4.5",
     "spinjs": "github:fgnass/spin.js@2.3.2",
     "text": "github:systemjs/plugin-text@0.0.7",
-    "github:akuznetsov-gridgain/angular-strap@fix-1852-2.3.6": {
-      "angular": "github:angular/bower-angular@1.5.1",
-      "angular-animate": "github:angular/bower-angular-animate@1.5.1",
-      "angular-motion": "github:mgcrea/angular-motion@0.4.3",
-      "angular-sanitize": "github:angular/bower-angular-sanitize@1.5.1"
-    },
     "github:angular-ui/bower-ui-grid@3.1.1": {
       "pdfmake": "github:bpampuch/pdfmake@0.1.20"
     },
@@ -80,6 +76,9 @@ System.config({
     "github:angular/bower-angular@1.5.1": {
       "jquery": "github:components/jquery@2.2.1"
     },
+    "github:btford/angular-socket-io@0.7.0": {
+      "socket.io-client": "github:socketio/socket.io-client@1.4.5"
+    },
     "github:darthwade/angular-loading@0.1.4": {
       "spinjs": "github:fgnass/spin.js@2.3.2"
     },
@@ -139,7 +138,6 @@ System.config({
       "vm-browserify": "npm:vm-browserify@0.0.4"
     },
     "github:krispo/angular-nvd3@1.0.5": {
-      "angular": "github:angular/bower-angular@1.5.1",
       "d3": "npm:d3@3.5.14",
       "nvd3": "npm:nvd3@1.8.1"
     },
@@ -147,6 +145,12 @@ System.config({
       "angular": "github:angular/bower-angular@1.5.1",
       "css": "github:systemjs/plugin-css@0.1.20"
     },
+    "github:mgcrea/angular-strap@2.3.7": {
+      "angular": "github:angular/bower-angular@1.5.1",
+      "angular-animate": "github:angular/bower-angular-animate@1.5.1",
+      "angular-motion": "github:mgcrea/angular-motion@0.4.3",
+      "angular-sanitize": "github:angular/bower-angular-sanitize@1.5.1"
+    },
     "github:twbs/bootstrap@3.3.6": {
       "jquery": "github:components/jquery@2.2.1"
     },

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/controllers/common-module.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/common-module.js b/modules/control-center-web/src/main/js/controllers/common-module.js
index a98ba2c..d4f692d 100644
--- a/modules/control-center-web/src/main/js/controllers/common-module.js
+++ b/modules/control-center-web/src/main/js/controllers/common-module.js
@@ -17,10 +17,21 @@
 
 var consoleModule = angular.module('ignite-web-console',
     [
-        'ngAnimate', 'ngSanitize', 'mgcrea.ngStrap', 'smart-table', 'treeControl', 'darthwade.dwLoading', 'ui.grid', 'ui.grid.autoResize', 'ui.grid.exporter', 'nvd3', 'dndLists'
+        'darthwade.dwLoading',
+        'smart-table',
+        'treeControl',
+        'ui.grid',
+        'ui.grid.saveState',
+        'ui.grid.selection',
+        'ui.grid.resizeColumns',
+        'ui.grid.autoResize',
+        'ui.grid.exporter',
+        'nvd3',
+        'dndLists'
         /* ignite:modules */
         , 'ignite-console'
         /* endignite */
+
         /* ignite:plugins */
         /* endignite */
     ])
@@ -2045,194 +2056,6 @@ consoleModule.controller('auth', ['$scope', '$focus', 'Auth', 'IgniteCountries',
     $focus('user_email');
 }]);
 
-// Download agent controller.
-consoleModule.service('$agentDownload', [
-    '$http', '$interval', '$rootScope', '$state', '$modal', '$loading', '$common',
-        function ($http, $interval, $rootScope, $state, $modal, $loading, $common) {
-        var scope = $rootScope.$new();
-
-        // Pre-fetch modal dialogs.
-        var _modal = $modal({scope: scope, templateUrl: '/templates/agent-download.html', show: false, backdrop: 'static'});
-
-        var _modalHide = _modal.hide;
-
-        var _modalAlertHide = function () {
-            $common.hideAlert();
-
-            _modalHide();
-        };
-
-        /**
-         * Special dialog hide function.
-         */
-        _modal.hide = function () {
-            _stopInterval();
-
-            _modalAlertHide();
-        };
-
-        /**
-         * Close dialog and go by specified link.
-         */
-        scope.back = function () {
-            _modal.hide();
-
-            if (_modal.backState)
-                $state.go(_modal.backState);
-        };
-
-        scope.downloadAgent = function () {
-            var lnk = document.createElement('a');
-
-            lnk.setAttribute('href', '/api/v1/agent/download/zip');
-            lnk.setAttribute('target', '_self');
-            lnk.setAttribute('download', null);
-            lnk.style.display = 'none';
-
-            document.body.appendChild(lnk);
-
-            lnk.click();
-
-            document.body.removeChild(lnk);
-        };
-
-        /**
-         * Base handler of exceptions on agent interaction
-         *
-         * @param errMsg Error message.
-         * @param status Error code.
-         * @param timedOut True if request timedOut.
-         */
-        function _handleException (errMsg, status, timedOut) {
-            if (_modal.skipSingleError)
-                _modal.skipSingleError = false;
-            else if (!_modal.$isShown) {
-                // Don't show missing node dialog on SQL demo enabling.
-                if (_modal.check.params && _modal.check.params.demo && timedOut || !_modal.updatePromise)
-                    return;
-
-                $loading.finish('loading');
-
-                _modal.$promise.then(_modal.show);
-            }
-
-            var nodeError = _.includes([401, 403, 500], status);
-
-            scope.nodeFailedConnection = nodeError || timedOut;
-
-            if (nodeError)
-                $common.showError(errMsg, 'top-right', 'body', true);
-        }
-
-        /**
-         * Start interval to agent listening.
-         */
-        function _startInterval(awaitFirstSuccess) {
-            _modal.skipSingleError = false;
-
-            // Stop refresh after first success.
-            _modal.awaitFirstSuccess = awaitFirstSuccess;
-
-            _modal.updatePromise = $interval(function () {
-                _tryWithAgent();
-            }, 5000, 0, false);
-
-            _tryWithAgent();
-        }
-
-        /**
-         * Stop interval to agent listening.
-         */
-        function _stopInterval() {
-            $interval.cancel(_modal.updatePromise);
-
-            _modal.updatePromise = null;
-        }
-
-        /**
-         * Try to access agent and execute specified function.
-         */
-        function _tryWithAgent() {
-            var _timeout = 3000,
-                _timedOut = false;
-
-            setTimeout(function () {
-                _timedOut = true;
-            }, _timeout);
-
-            $http.post(_modal.check.url, _modal.check.params, {timeout: _timeout})
-                .success(function (data) {
-                    if (_modal.awaitFirstSuccess)
-                        _stopInterval();
-
-                    $loading.finish('loading');
-
-                    _modal.check.cb(data, _modalAlertHide, _handleException);
-
-                    if (!_modal.skipSingleError && _modal.check.onConnect)
-                        _modal.check.onConnect();
-
-                    _modal.skipSingleError = true;
-                })
-                .error(function (errMsg, status) {
-                    _handleException(errMsg, status, _timedOut);
-                });
-        }
-
-        return {
-            /**
-             * Start listening topology from node.
-             *
-             * @param cb Function to execute by timer when topology received.
-             * @param onConnect Function to execute when agent connected to a grid.
-             * @param demo True if need work with demo grid.
-             * @param attr True if need receive nodes attributes.
-             * @param mtr True if need receive nodes metrics.
-             */
-            startTopologyListening: function (cb, onConnect, demo, attr, mtr) {
-                _modal.check = {
-                    url: '/api/v1/agent/topology',
-                    params: {demo: !!demo,  attr: !!attr, mtr: !!mtr},
-                    onConnect: onConnect,
-                    cb: cb
-                };
-
-                _modal.backState = 'base.configuration.clusters';
-
-                scope.agentGoal = 'execute sql statements';
-
-                scope.backText = 'Back to Configuration';
-
-                _startInterval();
-            },
-            /**
-             * Start awaiting agent start using ping.
-             *
-             * @param success Function to execute by timer when agent available.
-             */
-            awaitAgent: function (success) {
-                _modal.check = {
-                    url: '/api/v1/agent/ping',
-                    cb: success
-                };
-
-                _modal.backState = 'base.configuration.domains';
-
-                scope.agentGoal = 'import domain model from database schema';
-
-                scope.backText = 'Back to Domain models';
-
-                _startInterval(true);
-            },
-            /**
-             * Stop listening of agent by ping.
-             */
-            stopAwaitAgent: function () {
-                _stopInterval();
-            }
-        };
-    }]);
-
 // Navigation bar controller.
 consoleModule.controller('notebooks', ['$scope', '$modal', '$state', '$http', '$common',
     function ($scope, $modal, $state, $http, $common) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/706317f3/modules/control-center-web/src/main/js/controllers/domains-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/domains-controller.js b/modules/control-center-web/src/main/js/controllers/domains-controller.js
index 09a467a..0b88662 100644
--- a/modules/control-center-web/src/main/js/controllers/domains-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/domains-controller.js
@@ -17,8 +17,8 @@
 
 // Controller for Domain model screen.
 consoleModule.controller('domainsController', [
-    '$scope', '$http', '$state', '$filter', '$timeout', '$modal', '$common', '$focus', '$confirm', '$confirmBatch', '$clone', '$table', '$preview', '$loading', '$unsavedChangesGuard', '$agentDownload',
-    function ($scope, $http, $state, $filter, $timeout, $modal, $common, $focus, $confirm, $confirmBatch, $clone, $table, $preview, $loading, $unsavedChangesGuard, $agentDownload) {
+    '$scope', '$http', '$state', '$filter', '$timeout', '$modal', '$common', '$focus', '$confirm', '$confirmBatch', '$clone', '$table', '$preview', '$loading', '$unsavedChangesGuard', 'IgniteAgentMonitor',
+    function ($scope, $http, $state, $filter, $timeout, $modal, $common, $focus, $confirm, $confirmBatch, $clone, $table, $preview, $loading, $unsavedChangesGuard, IgniteAgentMonitor) {
         $unsavedChangesGuard.install($scope);
 
         $scope.ui = $common.formUI();
@@ -424,7 +424,7 @@ consoleModule.controller('domainsController', [
         var hideImportDomain = importDomainModal.hide;
 
         importDomainModal.hide = function () {
-            $agentDownload.stopAwaitAgent();
+            IgniteAgentMonitor.stopWatch();
 
             hideImportDomain();
         };
@@ -443,8 +443,8 @@ consoleModule.controller('domainsController', [
 
                 $scope.importDomain = {
                     demo: demo,
-                    action: 'drivers',
-                    jdbcDriversNotFound: false,
+                    action: demo ? 'connect' : 'drivers',
+                    jdbcDriversNotFound: demo,
                     schemas: [],
                     allSchemasSelected: false,
                     tables: [],
@@ -455,59 +455,45 @@ consoleModule.controller('domainsController', [
 
                 $scope.importDomain.loadingOptions = LOADING_JDBC_DRIVERS;
 
-                $agentDownload.awaitAgent(function (result, onSuccess, onException) {
-                    importDomainModal.$promise.then(importDomainModal.show);
+                IgniteAgentMonitor.startWatch({
+                        state: 'base.configuration.domains',
+                        text: 'Back to Domain models',
+                        goal: 'import domain model from database schema'
+                    })
+                    .then(function() {
+                        importDomainModal.$promise.then(importDomainModal.show);
+
+                        if (demo) {
+                            $scope.ui.packageNameUserInput = $scope.ui.packageName;
+                            $scope.ui.packageName = 'model';
+
+                            return;
+                        }
 
-                    // Get available JDBC drivers via agent.
-                    if ($scope.importDomain.action === 'drivers') {
+                        // Get available JDBC drivers via agent.
                         $loading.start('importDomainFromDb');
 
                         $scope.jdbcDriverJars = [];
                         $scope.ui.selectedJdbcDriverJar = {};
 
-                        $http.post('/api/v1/agent/drivers')
-                            .success(function (drivers) {
-                                onSuccess();
-
-                                if ($scope.importDomain.demo) {
-                                    $scope.ui.packageNamePrev = $scope.ui.packageName;
-                                    $scope.ui.packageName = 'model';
-                                }
-                                else if ($scope.ui.packageNamePrev) {
-                                    $scope.ui.packageName = $scope.ui.packageNamePrev;
-                                    $scope.ui.packageNamePrev = null;
-                                }
+                        return IgniteAgentMonitor.drivers()
+                            .then(function(drivers) {
+                                $scope.ui.packageName = $scope.ui.packageNameUserInput;
 
                                 if (drivers && drivers.length > 0) {
                                     drivers = _.sortBy(drivers, 'jdbcDriverJar');
 
-                                    if ($scope.importDomain.demo) {
-                                        var _h2DrvJar = _.find(drivers, function (drv) {
-                                            return drv.jdbcDriverJar.startsWith('h2');
-                                        });
-
-                                        if (_h2DrvJar) {
-                                            $scope.demoConnection.db = 'H2';
-                                            $scope.demoConnection.jdbcDriverJar = _h2DrvJar.jdbcDriverJar;
-                                        }
-                                        else {
-                                            $scope.demoConnection.db = 'General';
-                                            $scope.importDomain.button = 'Cancel';
-                                        }
-                                    }
-                                    else {
-                                        drivers.forEach(function (driver) {
-                                            $scope.jdbcDriverJars.push({
-                                                label: driver.jdbcDriverJar,
-                                                value: {
-                                                    jdbcDriverJar: driver.jdbcDriverJar,
-                                                    jdbcDriverClass: driver.jdbcDriverClass
-                                                }
-                                            });
+                                    drivers.forEach(function (drv) {
+                                        $scope.jdbcDriverJars.push({
+                                            label: drv.jdbcDriverJar,
+                                            value: {
+                                                jdbcDriverJar: drv.jdbcDriverJar,
+                                                jdbcDriverClass: drv.jdbcDriverCls
+                                            }
                                         });
+                                    });
 
-                                        $scope.ui.selectedJdbcDriverJar = $scope.jdbcDriverJars[0].value;
-                                    }
+                                    $scope.ui.selectedJdbcDriverJar = $scope.jdbcDriverJars[0].value;
 
                                     $common.confirmUnsavedChanges($scope.ui.isDirty(), function () {
                                         importDomainModal.$promise.then(function () {
@@ -524,16 +510,12 @@ consoleModule.controller('domainsController', [
                                     $scope.importDomain.button = 'Cancel';
                                 }
                             })
-                            .error(function (errMsg, status) {
-                                onException(errMsg, status);
-                            })
                             .finally(function () {
                                 $scope.importDomain.info = INFO_CONNECT_TO_DB;
 
                                 $loading.finish('importDomainFromDb');
                             });
-                    }
-                });
+                    })
             });
         };
 
@@ -541,15 +523,18 @@ consoleModule.controller('domainsController', [
          * Load list of database schemas.
          */
         function _loadSchemas() {
-            $loading.start('importDomainFromDb');
+            IgniteAgentMonitor.awaitAgent()
+                .then(function() {
+                    $loading.start('importDomainFromDb');
 
-            var preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
+                    var preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
 
-            if (!$scope.importDomain.demo)
-                _savePreset(preset);
+                    if (!$scope.importDomain.demo)
+                        _savePreset(preset);
 
-            $http.post('/api/v1/agent/schemas', preset)
-                .success(function (schemas) {
+                    return IgniteAgentMonitor.schemas(preset)
+                })
+                .then(function(schemas) {
                     $scope.importDomain.schemas = _.map(schemas, function (schema) {
                         return {use: false, name: schema};
                     });
@@ -566,7 +551,7 @@ consoleModule.controller('domainsController', [
                     $scope.importDomain.info = INFO_SELECT_SCHEMAS;
                     $scope.importDomain.loadingOptions = LOADING_TABLES;
                 })
-                .error(function (errMsg) {
+                .catch(function(errMsg) {
                     $common.showError(errMsg);
                 })
                 .finally(function () {
@@ -611,21 +596,24 @@ consoleModule.controller('domainsController', [
          * Load list of database tables.
          */
         function _loadTables() {
-            $loading.start('importDomainFromDb');
+            IgniteAgentMonitor.awaitAgent()
+                .then(function() {
+                    $loading.start('importDomainFromDb');
 
-            $scope.importDomain.allTablesSelected = false;
+                    $scope.importDomain.allTablesSelected = false;
 
-            var preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
+                    var preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
 
-            preset.schemas = [];
+                    preset.schemas = [];
 
-            _.forEach($scope.importDomain.schemas, function (schema) {
-                if (schema.use)
-                    preset.schemas.push(schema.name);
-            });
+                    _.forEach($scope.importDomain.schemas, function (schema) {
+                        if (schema.use)
+                            preset.schemas.push(schema.name);
+                    });
 
-            $http.post('/api/v1/agent/tables', preset)
-                .success(function (tables) {
+                    return IgniteAgentMonitor.tables(preset);
+                })
+                .then(function (tables) {
                     _importCachesOrTemplates = [DFLT_PARTITIONED_CACHE, DFLT_REPLICATED_CACHE].concat($scope.caches);
 
                     _fillCommonCachesOrTemplates($scope.importCommon)($scope.importCommon.action);
@@ -646,7 +634,7 @@ consoleModule.controller('domainsController', [
                     $scope.importDomain.tables = tables;
                     $scope.importDomain.info = INFO_SELECT_TABLES;
                 })
-                .error(function (errMsg) {
+                .catch(function(errMsg) {
                     $common.showError(errMsg);
                 })
                 .finally(function () {
@@ -989,7 +977,8 @@ consoleModule.controller('domainsController', [
                             _saveBatch(_.filter(batch, function (item) {
                                 return !item.skip;
                             }));
-                        }, function () {
+                        })
+                        .catch(function () {
                             $common.showError('Importing of domain models interrupted by user.');
                         });
                 else
@@ -1014,12 +1003,8 @@ consoleModule.controller('domainsController', [
 
             if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
                 importDomainModal.hide();
-            else if (act === 'connect') {
-                if ($scope.importDomain.demo && $scope.demoConnection.db !== 'H2')
-                    importDomainModal.hide();
-                else
-                    _loadSchemas();
-            }
+            else if (act === 'connect')
+                _loadSchemas();
             else if (act === 'schemas')
                 _loadTables();
             else if (act === 'tables')
@@ -1036,13 +1021,8 @@ consoleModule.controller('domainsController', [
             if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
                 return 'Resolve issue with JDBC drivers<br>Close this dialog and try again';
 
-            if (act === 'connect') {
-                if ($scope.importDomain.demo && $scope.demoConnection.db !== 'H2')
-                    return 'Resolve issue with H2 database driver<br>Close this dialog and try again';
-
-                if (importDomainNextAvailable)
-                    return 'Click to load list of schemas from database';
-            }
+            if (act === 'connect' || act === 'drivers')
+                return 'Click to load list of schemas from database';
 
             if (act === 'schemas')
                 return importDomainNextAvailable ? 'Click to load list of tables from database' : 'Select schemas to continue';