ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akuznet...@apache.org
Subject [01/52] ignite git commit: Web Console beta-3.
Date Fri, 09 Sep 2016 03:26:29 GMT
Repository: ignite
Updated Branches:
  refs/heads/master 31b9bb84d -> 39ec7d06b


http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
new file mode 100644
index 0000000..1b4b565
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.agent.handlers;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.codec.Charsets;
+import org.apache.http.Header;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.ignite.console.agent.AgentConfiguration;
+import org.apache.ignite.console.demo.AgentClusterDemo;
+import org.apache.log4j.Logger;
+
+import static org.apache.ignite.console.agent.AgentConfiguration.DFLT_NODE_PORT;
+
+/**
+ * API to translate REST requests to Ignite cluster.
+ */
+public class RestHandler extends AbstractHandler {
+    /** */
+    private static final Logger log = Logger.getLogger(RestHandler.class.getName());
+
+    /** */
+    private final AgentConfiguration cfg;
+
+    /** */
+    private CloseableHttpClient httpClient;
+
+    /**
+     * @param cfg Config.
+     */
+    public RestHandler(AgentConfiguration cfg) {
+        this.cfg = cfg;
+    }
+
+    /**
+     * Start HTTP client for communication with node via REST.
+     */
+    public void start() {
+        httpClient = HttpClientBuilder.create().build();
+    }
+
+    /**
+     * Stop HTTP client.
+     */
+    public void stop() {
+        if (httpClient != null) {
+            try {
+                httpClient.close();
+            }
+            catch (IOException ignore) {
+                // No-op.
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override public Object execute(Map<String, Object> args) throws Exception {
+        if (log.isDebugEnabled())
+            log.debug("Start parse REST command args: " + args);
+
+        String uri = null;
+
+        if (args.containsKey("uri"))
+            uri = args.get("uri").toString();
+
+        Map<String, Object> params = null;
+
+        if (args.containsKey("params"))
+            params = (Map<String, Object>)args.get("params");
+
+        if (!args.containsKey("demo"))
+            throw new IllegalArgumentException("Missing demo flag in arguments: " + args);
+
+        boolean demo = (boolean)args.get("demo");
+
+        if (!args.containsKey("method"))
+            throw new IllegalArgumentException("Missing method in arguments: " + args);
+
+        String mtd = args.get("method").toString();
+
+        Map<String, Object> headers = null;
+
+        if (args.containsKey("headers"))
+            headers = (Map<String, Object>)args.get("headers");
+
+        String body = null;
+
+        if (args.containsKey("body"))
+            body = args.get("body").toString();
+
+        return executeRest(uri, params, demo, mtd, headers, body);
+    }
+
+    /**
+     * @param uri Url.
+     * @param params Params.
+     * @param demo Use demo node.
+     * @param mtd Method.
+     * @param headers Headers.
+     * @param body Body.
+     */
+    protected RestResult executeRest(String uri, Map<String, Object> params, boolean demo,
+        String mtd, Map<String, Object> headers, String body) throws IOException, URISyntaxException {
+        if (log.isDebugEnabled())
+            log.debug("Start execute REST command [method=" + mtd + ", uri=/" + (uri == null ? "" : uri) +
+                ", parameters=" + params + "]");
+
+        final URIBuilder builder;
+
+        if (demo) {
+            // try start demo if needed.
+            AgentClusterDemo.testDrive(cfg);
+
+            // null if demo node not started yet.
+            if (cfg.demoNodeUri() == null)
+                return RestResult.fail("Demo node is not started yet.", 404);
+
+            builder = new URIBuilder(cfg.demoNodeUri());
+        }
+        else
+            builder = new URIBuilder(cfg.nodeUri());
+
+        if (builder.getPort() == -1)
+            builder.setPort(DFLT_NODE_PORT);
+
+        if (uri != null) {
+            if (!uri.startsWith("/") && !cfg.nodeUri().endsWith("/"))
+                uri = '/' + uri;
+
+            builder.setPath(uri);
+        }
+
+        if (params != null) {
+            for (Map.Entry<String, Object> entry : params.entrySet()) {
+                if (entry.getValue() != null)
+                    builder.addParameter(entry.getKey(), entry.getValue().toString());
+            }
+        }
+
+        HttpRequestBase httpReq = null;
+
+        try {
+            if ("GET".equalsIgnoreCase(mtd))
+                httpReq = new HttpGet(builder.build());
+            else if ("POST".equalsIgnoreCase(mtd)) {
+                HttpPost post;
+
+                if (body == null) {
+                    List<NameValuePair> nvps = builder.getQueryParams();
+
+                    builder.clearParameters();
+
+                    post = new HttpPost(builder.build());
+
+                    if (!nvps.isEmpty())
+                        post.setEntity(new UrlEncodedFormEntity(nvps));
+                }
+                else {
+                    post = new HttpPost(builder.build());
+
+                    post.setEntity(new StringEntity(body));
+                }
+
+                httpReq = post;
+            }
+            else
+                throw new IOException("Unknown HTTP-method: " + mtd);
+
+            if (headers != null) {
+                for (Map.Entry<String, Object> entry : headers.entrySet())
+                    httpReq.addHeader(entry.getKey(), entry.getValue() == null ? null : entry.getValue().toString());
+            }
+
+            try (CloseableHttpResponse resp = httpClient.execute(httpReq)) {
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+                resp.getEntity().writeTo(out);
+
+                Charset charset = Charsets.UTF_8;
+
+                Header encodingHdr = resp.getEntity().getContentEncoding();
+
+                if (encodingHdr != null) {
+                    String encoding = encodingHdr.getValue();
+
+                    charset = Charsets.toCharset(encoding);
+                }
+
+                return RestResult.success(resp.getStatusLine().getStatusCode(), new String(out.toByteArray(), charset));
+            }
+            catch (ConnectException e) {
+                log.info("Failed connect to node and execute REST command [uri=" + builder.build() + "]");
+
+                return RestResult.fail("Failed connect to node and execute REST command.", 404);
+            }
+        }
+        finally {
+            if (httpReq != null)
+                httpReq.reset();
+        }
+    }
+
+    /**
+     * Request result.
+     */
+    public static class RestResult {
+        /** The field contains description of error if server could not handle the request. */
+        public final String error;
+
+        /** REST http code. */
+        public final int code;
+
+        /** The field contains result of command. */
+        public final String data;
+
+        /**
+         * @param error The field contains description of error if server could not handle the request.
+         * @param resCode REST http code.
+         * @param res The field contains result of command.
+         */
+        private RestResult(String error, int resCode, String res) {
+            this.error = error;
+            this.code = resCode;
+            this.data = res;
+        }
+
+        /**
+         * @param error The field contains description of error if server could not handle the request.
+         * @param restCode REST http code.
+         * @return Request result.
+         */
+        public static RestResult fail(String error, int restCode) {
+            return new RestResult(error, restCode, null);
+        }
+
+        /**
+         * @param code REST http code.
+         * @param data The field contains result of command.
+         * @return Request result.
+         */
+        public static RestResult success(int code, String data) {
+            return new RestResult(null, code, data);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
new file mode 100644
index 0000000..09189b5
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
@@ -0,0 +1,641 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+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.CacheAtomicityMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.QueryIndexType;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+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.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.logger.log4j.Log4JLogger;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.log4j.Logger;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_PERFORMANCE_SUGGESTIONS_DISABLED;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_NO_ASCII;
+import static org.apache.ignite.events.EventType.EVTS_DISCOVERY;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_JETTY_ADDRS;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_JETTY_PORT;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+
+/**
+ * Demo for cluster features like SQL and Monitoring.
+ *
+ * Cache will be created and populated with data to query.
+ */
+public class AgentClusterDemo {
+    /** */
+    private static final Logger log = Logger.getLogger(AgentClusterDemo.class.getName());
+
+    /** */
+    private static final AtomicBoolean initLatch = new AtomicBoolean();
+
+    /** */
+    private static final int NODE_CNT = 3;
+
+    /** */
+    private static final String COUNTRY_CACHE_NAME = "CountryCache";
+
+    /** */
+    private static final String DEPARTMENT_CACHE_NAME = "DepartmentCache";
+
+    /** */
+    private static final String EMPLOYEE_CACHE_NAME = "EmployeeCache";
+
+    /** */
+    private static final String PARKING_CACHE_NAME = "ParkingCache";
+
+    /** */
+    private static final String CAR_CACHE_NAME = "CarCache";
+
+    /** */
+    private static final Set<String> DEMO_CACHES = new HashSet<>(Arrays.asList(COUNTRY_CACHE_NAME,
+        DEPARTMENT_CACHE_NAME, EMPLOYEE_CACHE_NAME, PARKING_CACHE_NAME, CAR_CACHE_NAME));
+
+    /** */
+    private static final Random rnd = new Random();
+
+    /** Countries count. */
+    private static final int CNTR_CNT = 10;
+
+    /** Departments count */
+    private static final int DEP_CNT = 100;
+
+    /** Employees count. */
+    private static final int EMPL_CNT = 1000;
+
+    /** Countries count. */
+    private static final int CAR_CNT = 100;
+
+    /** Departments count */
+    private static final int PARK_CNT = 10;
+
+    /** Counter for threads in pool. */
+    private static final AtomicInteger THREAD_CNT = new AtomicInteger(0);
+
+    /**
+     * Create base cache configuration.
+     *
+     * @param name cache name.
+     * @return Cache configuration with basic properties set.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheConfiguration(String name) {
+        CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(name);
+
+        ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
+        ccfg.setStartSize(100);
+        ccfg.setStatisticsEnabled(true);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheCountry.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheCountry() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(COUNTRY_CACHE_NAME);
+
+        // Configure cacheCountry types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // COUNTRY.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Country.class.getName());
+
+        // Query fields for COUNTRY.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+        qryFlds.put("population", "java.lang.Integer");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheDepartment() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(DEPARTMENT_CACHE_NAME);
+
+        // Configure cacheDepartment types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // DEPARTMENT.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Department.class.getName());
+
+        // Query fields for DEPARTMENT.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("countryId", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheEmployee() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(EMPLOYEE_CACHE_NAME);
+
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+        ccfg.setBackups(1);
+
+        // Configure cacheEmployee types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // EMPLOYEE.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Employee.class.getName());
+
+        // Query fields for EMPLOYEE.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("departmentId", "java.lang.Integer");
+        qryFlds.put("managerId", "java.lang.Integer");
+        qryFlds.put("firstName", "java.lang.String");
+        qryFlds.put("lastName", "java.lang.String");
+        qryFlds.put("email", "java.lang.String");
+        qryFlds.put("phoneNumber", "java.lang.String");
+        qryFlds.put("hireDate", "java.sql.Date");
+        qryFlds.put("job", "java.lang.String");
+        qryFlds.put("salary", "java.lang.Double");
+
+        type.setFields(qryFlds);
+
+        // Indexes for EMPLOYEE.
+        Collection<QueryIndex> indexes = new ArrayList<>();
+
+        QueryIndex idx = new QueryIndex();
+
+        idx.setName("EMP_NAMES");
+        idx.setIndexType(QueryIndexType.SORTED);
+        LinkedHashMap<String, Boolean> indFlds = new LinkedHashMap<>();
+
+        indFlds.put("firstName", Boolean.FALSE);
+        indFlds.put("lastName", Boolean.FALSE);
+
+        idx.setFields(indFlds);
+
+        indexes.add(idx);
+        indexes.add(new QueryIndex("salary", QueryIndexType.SORTED, false, "EMP_SALARY"));
+
+        type.setIndexes(indexes);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheParking() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(PARKING_CACHE_NAME);
+
+        // Configure cacheParking types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // PARKING.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Parking.class.getName());
+
+        // Query fields for PARKING.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+        qryFlds.put("capacity", "java.lang.Integer");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheCar() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(CAR_CACHE_NAME);
+
+        // Configure cacheCar types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // CAR.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Car.class.getName());
+
+        // Query fields for CAR.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("parkingId", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure node.
+     * @param gridIdx Grid name index.
+     * @param client If {@code true} then start client node.
+     * @return IgniteConfiguration
+     */
+    private static  IgniteConfiguration igniteConfiguration(int gridIdx, boolean client) {
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setGridName((client ? "demo-server-" : "demo-client-") + gridIdx);
+        cfg.setLocalHost("127.0.0.1");
+        cfg.setIncludeEventTypes(EVTS_DISCOVERY);
+
+        TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryVmIpFinder();
+
+        ipFinder.setAddresses(Collections.singletonList("127.0.0.1:60900.." + (60900 + NODE_CNT - 1)));
+
+        // Configure discovery SPI.
+        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
+
+        discoSpi.setLocalPort(60900);
+        discoSpi.setIpFinder(ipFinder);
+
+        cfg.setDiscoverySpi(discoSpi);
+
+        TcpCommunicationSpi commSpi = new TcpCommunicationSpi();
+
+        commSpi.setSharedMemoryPort(-1);
+        commSpi.setLocalPort(60800);
+
+        cfg.setCommunicationSpi(commSpi);
+        cfg.setGridLogger(new Log4JLogger(log));
+        cfg.setMetricsLogFrequency(0);
+        cfg.getConnectorConfiguration().setPort(60700);
+
+        if (client)
+            cfg.setClientMode(true);
+
+        cfg.setCacheConfiguration(cacheCountry(), cacheDepartment(), cacheEmployee(), cacheParking(), cacheCar());
+
+        cfg.setSwapSpaceSpi(new FileSwapSpaceSpi());
+
+        return cfg;
+    }
+
+    /**
+     * @param val Value to round.
+     * @param places Numbers after point.
+     * @return Rounded value;
+     */
+    private static double round(double val, int places) {
+        if (places < 0)
+            throw new IllegalArgumentException();
+
+        long factor = (long)Math.pow(10, places);
+
+        val *= factor;
+
+        long tmp = Math.round(val);
+
+        return (double)tmp / factor;
+    }
+
+    /**
+     * @param ignite Ignite.
+     * @param range Time range in milliseconds.
+     */
+    private static void populateCacheEmployee(Ignite ignite, long range) {
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Start employees population with data...");
+
+        IgniteCache<Integer, Country> cacheCountry = ignite.cache(COUNTRY_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < CNTR_CNT; i++, n++)
+            cacheCountry.put(i, new Country(i, "Country #" + n, n * 10000000));
+
+        IgniteCache<Integer, Department> cacheDepartment = ignite.cache(DEPARTMENT_CACHE_NAME);
+
+        IgniteCache<Integer, Employee> cacheEmployee = ignite.cache(EMPLOYEE_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < DEP_CNT; i++, n++) {
+            cacheDepartment.put(i, new Department(n, rnd.nextInt(CNTR_CNT), "Department #" + n));
+
+            double r = rnd.nextDouble();
+
+            cacheEmployee.put(i, new Employee(i, rnd.nextInt(DEP_CNT), null, "First name manager #" + n,
+                "Last name manager #" + n, "Email manager #" + n, "Phone number manager #" + n,
+                new java.sql.Date((long)(r * range)), "Job manager #" + n, 1000 + round(r * 4000, 2)));
+        }
+
+        for (int i = 0, n = 1; i < EMPL_CNT; i++, n++) {
+            Integer depId = rnd.nextInt(DEP_CNT);
+
+            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)));
+        }
+
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Finished employees population.");
+    }
+
+    /**
+     * @param ignite Ignite.
+     */
+    private static void populateCacheCar(Ignite ignite) {
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Start cars population...");
+
+        IgniteCache<Integer, Parking> cacheParking = ignite.cache(PARKING_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < PARK_CNT; i++, n++)
+            cacheParking.put(i, new Parking(i, "Parking #" + n, n * 10));
+
+        IgniteCache<Integer, Car> cacheCar = ignite.cache(CAR_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < CAR_CNT; i++, n++)
+            cacheCar.put(i, new Car(i, rnd.nextInt(PARK_CNT), "Car #" + n));
+
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Finished cars population.");
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.
+     *
+     * @param corePoolSize Number of threads to keep in the pool, even if they are idle.
+     * @param threadName Part of thread name that would be used by thread factory.
+     * @return Newly created scheduled thread pool.
+     */
+    private static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, final String threadName) {
+        ScheduledExecutorService srvc = Executors.newScheduledThreadPool(corePoolSize, new ThreadFactory() {
+            @Override public Thread newThread(Runnable r) {
+                Thread thread = new Thread(r, String.format("%s-%d", threadName, THREAD_CNT.getAndIncrement()));
+
+                thread.setDaemon(true);
+
+                return thread;
+            }
+        });
+
+        ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor)srvc;
+
+        // Setting up shutdown policy.
+        executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+        executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+
+        return srvc;
+    }
+
+    /**
+     * Starts read and write from cache in background.
+     *
+     * @param ignite Ignite.
+     * @param cnt - maximum count read/write key
+     */
+    private static void startLoad(final Ignite ignite, final int cnt) {
+        final long diff = new java.util.Date().getTime();
+
+        populateCacheEmployee(ignite, diff);
+        populateCacheCar(ignite);
+
+        ScheduledExecutorService cachePool = newScheduledThreadPool(2, "demo-sql-load-cache-tasks");
+
+        cachePool.scheduleWithFixedDelay(new Runnable() {
+            @Override public void run() {
+                try {
+                    for (String cacheName : ignite.cacheNames()) {
+                        if (!DEMO_CACHES.contains(cacheName)) {
+                            IgniteCache<Integer, String> otherCache = ignite.cache(cacheName);
+
+                            if (otherCache != null) {
+                                for (int i = 0, n = 1; i < cnt; i++, n++) {
+                                    Integer key = rnd.nextInt(1000);
+
+                                    String val = otherCache.get(key);
+
+                                    if (val == null)
+                                        otherCache.put(key, "other-" + key);
+                                    else if (rnd.nextInt(100) < 30)
+                                        otherCache.remove(key);
+                                }
+                            }
+                        }
+                    }
+
+                    IgniteCache<Integer, Employee> cacheEmployee = ignite.cache(EMPLOYEE_CACHE_NAME);
+
+                    if (cacheEmployee != null)
+                        try(Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
+                            for (int i = 0, n = 1; i < cnt; i++, n++) {
+                                Integer id = rnd.nextInt(EMPL_CNT);
+
+                                Integer depId = rnd.nextInt(DEP_CNT);
+
+                                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)));
+
+                                if (rnd.nextBoolean())
+                                    cacheEmployee.remove(rnd.nextInt(EMPL_CNT));
+
+                                cacheEmployee.get(rnd.nextInt(EMPL_CNT));
+                            }
+
+                            if (rnd.nextInt(100) > 20)
+                                tx.commit();
+                        }
+                }
+                catch (Throwable e) {
+                    if (!e.getMessage().contains("cache is stopped"))
+                        ignite.log().error("Cache write task execution error", e);
+                }
+            }
+        }, 10, 3, TimeUnit.SECONDS);
+
+        cachePool.scheduleWithFixedDelay(new Runnable() {
+            @Override public void run() {
+                try {
+                    IgniteCache<Integer, Car> cache = ignite.cache(CAR_CACHE_NAME);
+
+                    if (cache != null)
+                        for (int i = 0; i < cnt; i++) {
+                            Integer carId = rnd.nextInt(CAR_CNT);
+
+                            cache.put(carId, new Car(carId, rnd.nextInt(PARK_CNT), "Car #" + (i + 1)));
+
+                            if (rnd.nextBoolean())
+                                cache.remove(rnd.nextInt(CAR_CNT));
+                        }
+                }
+                catch (IllegalStateException ignored) {
+                    // No-op.
+                }
+                catch (Throwable e) {
+                    if (!e.getMessage().contains("cache is stopped"))
+                        ignite.log().error("Cache write task execution error", e);
+                }
+            }
+        }, 10, 3, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Start ignite node with cacheEmployee and populate it with data.
+     */
+    public static boolean testDrive(AgentConfiguration acfg) {
+        if (initLatch.compareAndSet(false, true)) {
+            log.info("DEMO: Starting embedded nodes for demo...");
+
+            System.setProperty(IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE, "1");
+            System.setProperty(IGNITE_PERFORMANCE_SUGGESTIONS_DISABLED, "true");
+            System.setProperty(IGNITE_UPDATE_NOTIFIER, "false");
+
+            System.setProperty(IGNITE_JETTY_PORT, "60800");
+            System.setProperty(IGNITE_NO_ASCII, "true");
+
+            try {
+                IgniteEx ignite = (IgniteEx)Ignition.start(igniteConfiguration(0, false));
+
+                final AtomicInteger cnt = new AtomicInteger(0);
+
+                final ScheduledExecutorService execSrv = Executors.newSingleThreadScheduledExecutor();
+
+                execSrv.scheduleAtFixedRate(new Runnable() {
+                    @Override public void run() {
+                        int idx = cnt.incrementAndGet();
+
+                        try {
+                            Ignition.start(igniteConfiguration(idx, idx == NODE_CNT));
+                        }
+                        catch (Throwable e) {
+                            log.error("DEMO: Failed to start embedded node: " + e.getMessage());
+                        }
+                        finally {
+                            if (idx == NODE_CNT)
+                                execSrv.shutdown();
+                        }
+                    }
+                }, 10, 10, TimeUnit.SECONDS);
+
+                if (log.isDebugEnabled())
+                    log.debug("DEMO: Started embedded nodes with indexed enabled caches...");
+
+                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);
+
+                if (F.isEmpty(host) || port == null) {
+                    log.error("DEMO: Failed to start embedded node with rest!");
+
+                    return false;
+                }
+
+                acfg.demoNodeUri(String.format("http://%s:%d", host, port));
+
+                log.info("DEMO: Embedded nodes for sql and monitoring demo successfully started");
+
+                startLoad(ignite, 20);
+            }
+            catch (Exception e) {
+                log.error("DEMO: Failed to start embedded node for sql and monitoring demo!", e);
+
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
new file mode 100644
index 0000000..4683dd8
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.log4j.Logger;
+import org.h2.tools.RunScript;
+import org.h2.tools.Server;
+
+import static org.apache.ignite.console.agent.AgentUtils.resolvePath;
+
+/**
+ * Demo for metadata load from database.
+ *
+ * H2 database will be started and several tables will be created.
+ */
+public class AgentMetadataDemo {
+    /** */
+    private static final Logger log = Logger.getLogger(AgentMetadataDemo.class.getName());
+
+    /** */
+    private static final AtomicBoolean initLatch = new AtomicBoolean();
+
+    /**
+     * @param jdbcUrl Connection url.
+     * @return true if url is used for test-drive.
+     */
+    public static boolean isTestDriveUrl(String jdbcUrl) {
+        return "jdbc:h2:mem:demo-db".equals(jdbcUrl);
+    }
+
+    /**
+     * Start H2 database and populate it with several tables.
+     */
+    public static Connection testDrive() throws SQLException {
+        if (initLatch.compareAndSet(false, true)) {
+            log.info("DEMO: Prepare in-memory H2 database...");
+
+            try {
+                Connection conn = DriverManager.getConnection("jdbc:h2:mem:demo-db;DB_CLOSE_DELAY=-1", "sa", "");
+
+                File sqlScript = resolvePath("demo/db-init.sql");
+
+                //noinspection ConstantConditions
+                RunScript.execute(conn, new FileReader(sqlScript));
+
+                log.info("DEMO: Sample tables created.");
+
+                conn.close();
+
+                Server.createTcpServer("-tcpDaemon").start();
+
+                log.info("DEMO: TcpServer stared.");
+
+                log.info("DEMO: JDBC URL for test drive metadata load: jdbc:h2:mem:demo-db");
+            }
+            catch (SQLException e) {
+                log.error("DEMO: Failed to start test drive for metadata!", e);
+
+                throw e;
+            }
+            catch (FileNotFoundException | NullPointerException e) {
+                log.error("DEMO: Failed to find demo database init script file: demo/db-init.sql");
+
+                throw new SQLException("Failed to start demo for metadata", e);
+            }
+        }
+
+        return DriverManager.getConnection("jdbc:h2:mem:demo-db;DB_CLOSE_DELAY=-1", "sa", "");
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
new file mode 100644
index 0000000..f351efc
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Car definition.
+ */
+public class Car implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for parkingId. */
+    private int parkingId;
+
+    /** Value for name. */
+    private String name;
+
+    /**
+     * Empty constructor.
+     */
+    public Car() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Car(
+        int id,
+        int parkingId,
+        String name
+    ) {
+        this.id = id;
+        this.parkingId = parkingId;
+        this.name = name;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets parkingId.
+     *
+     * @return Value for parkingId.
+     */
+    public int getParkingId() {
+        return parkingId;
+    }
+
+    /**
+     * Sets parkingId.
+     *
+     * @param parkingId New value for parkingId.
+     */
+    public void setParkingId(int parkingId) {
+        this.parkingId = parkingId;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Car))
+            return false;
+
+        Car that = (Car)o;
+
+        if (id != that.id)
+            return false;
+
+        if (parkingId != that.parkingId)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + parkingId;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Car [id=" + id +
+            ", parkingId=" + parkingId +
+            ", name=" + name +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
new file mode 100644
index 0000000..348928b
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Country definition.
+ */
+public class Country implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for name. */
+    private String name;
+
+    /** Value for population. */
+    private int population;
+
+    /**
+     * Empty constructor.
+     */
+    public Country() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Country(
+        int id,
+        String name,
+        int population
+    ) {
+        this.id = id;
+        this.name = name;
+        this.population = population;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Gets population.
+     *
+     * @return Value for population.
+     */
+    public int getPopulation() {
+        return population;
+    }
+
+    /**
+     * Sets population.
+     *
+     * @param population New value for population.
+     */
+    public void setPopulation(int population) {
+        this.population = population;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Country))
+            return false;
+
+        Country that = (Country)o;
+
+        if (id != that.id)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        if (population != that.population)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        res = 31 * res + population;
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Country [id=" + id +
+            ", name=" + name +
+            ", population=" + population +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
new file mode 100644
index 0000000..1c2f3b2
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Department definition.
+ */
+public class Department implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for countryId. */
+    private int countryId;
+
+    /** Value for name. */
+    private String name;
+
+    /**
+     * Empty constructor.
+     */
+    public Department() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Department(
+        int id,
+        int countryId,
+        String name
+    ) {
+        this.id = id;
+        this.countryId = countryId;
+        this.name = name;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets countryId.
+     *
+     * @return Value for countryId.
+     */
+    public int getCountryId() {
+        return countryId;
+    }
+
+    /**
+     * Sets countryId.
+     *
+     * @param countryId New value for countryId.
+     */
+    public void setCountryId(int countryId) {
+        this.countryId = countryId;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Department))
+            return false;
+
+        Department that = (Department)o;
+
+        if (id != that.id)
+            return false;
+
+        if (countryId != that.countryId)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + countryId;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Department [id=" + id +
+            ", countryId=" + countryId +
+            ", name=" + name +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
new file mode 100644
index 0000000..a3e7eba
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
@@ -0,0 +1,356 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+import java.sql.Date;
+
+/**
+ * Employee definition.
+ */
+public class Employee implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for departmentId. */
+    private int departmentId;
+
+    /** Value for managerId. */
+    private Integer managerId;
+
+    /** Value for firstName. */
+    private String firstName;
+
+    /** Value for lastName. */
+    private String lastName;
+
+    /** Value for email. */
+    private String email;
+
+    /** Value for phoneNumber. */
+    private String phoneNumber;
+
+    /** Value for hireDate. */
+    private Date hireDate;
+
+    /** Value for job. */
+    private String job;
+
+    /** Value for salary. */
+    private Double salary;
+
+    /**
+     * Empty constructor.
+     */
+    public Employee() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Employee(
+        int id,
+        int departmentId,
+        Integer managerId,
+        String firstName,
+        String lastName,
+        String email,
+        String phoneNumber,
+        Date hireDate,
+        String job,
+        Double salary
+    ) {
+        this.id = id;
+        this.departmentId = departmentId;
+        this.managerId = managerId;
+        this.firstName = firstName;
+        this.lastName = lastName;
+        this.email = email;
+        this.phoneNumber = phoneNumber;
+        this.hireDate = hireDate;
+        this.job = job;
+        this.salary = salary;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets departmentId.
+     *
+     * @return Value for departmentId.
+     */
+    public int getDepartmentId() {
+        return departmentId;
+    }
+
+    /**
+     * Sets departmentId.
+     *
+     * @param departmentId New value for departmentId.
+     */
+    public void setDepartmentId(int departmentId) {
+        this.departmentId = departmentId;
+    }
+
+    /**
+     * Gets managerId.
+     *
+     * @return Value for managerId.
+     */
+    public Integer getManagerId() {
+        return managerId;
+    }
+
+    /**
+     * Sets managerId.
+     *
+     * @param managerId New value for managerId.
+     */
+    public void setManagerId(Integer managerId) {
+        this.managerId = managerId;
+    }
+
+    /**
+     * Gets firstName.
+     *
+     * @return Value for firstName.
+     */
+    public String getFirstName() {
+        return firstName;
+    }
+
+    /**
+     * Sets firstName.
+     *
+     * @param firstName New value for firstName.
+     */
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+
+    /**
+     * Gets lastName.
+     *
+     * @return Value for lastName.
+     */
+    public String getLastName() {
+        return lastName;
+    }
+
+    /**
+     * Sets lastName.
+     *
+     * @param lastName New value for lastName.
+     */
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+    }
+
+    /**
+     * Gets email.
+     *
+     * @return Value for email.
+     */
+    public String getEmail() {
+        return email;
+    }
+
+    /**
+     * Sets email.
+     *
+     * @param email New value for email.
+     */
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    /**
+     * Gets phoneNumber.
+     *
+     * @return Value for phoneNumber.
+     */
+    public String getPhoneNumber() {
+        return phoneNumber;
+    }
+
+    /**
+     * Sets phoneNumber.
+     *
+     * @param phoneNumber New value for phoneNumber.
+     */
+    public void setPhoneNumber(String phoneNumber) {
+        this.phoneNumber = phoneNumber;
+    }
+
+    /**
+     * Gets hireDate.
+     *
+     * @return Value for hireDate.
+     */
+    public Date getHireDate() {
+        return hireDate;
+    }
+
+    /**
+     * Sets hireDate.
+     *
+     * @param hireDate New value for hireDate.
+     */
+    public void setHireDate(Date hireDate) {
+        this.hireDate = hireDate;
+    }
+
+    /**
+     * Gets job.
+     *
+     * @return Value for job.
+     */
+    public String getJob() {
+        return job;
+    }
+
+    /**
+     * Sets job.
+     *
+     * @param job New value for job.
+     */
+    public void setJob(String job) {
+        this.job = job;
+    }
+
+    /**
+     * Gets salary.
+     *
+     * @return Value for salary.
+     */
+    public Double getSalary() {
+        return salary;
+    }
+
+    /**
+     * Sets salary.
+     *
+     * @param salary New value for salary.
+     */
+    public void setSalary(Double salary) {
+        this.salary = salary;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Employee))
+            return false;
+
+        Employee that = (Employee)o;
+
+        if (id != that.id)
+            return false;
+
+        if (departmentId != that.departmentId)
+            return false;
+
+        if (managerId != null ? !managerId.equals(that.managerId) : that.managerId != null)
+            return false;
+
+        if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != null)
+            return false;
+
+        if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != null)
+            return false;
+
+        if (email != null ? !email.equals(that.email) : that.email != null)
+            return false;
+
+        if (phoneNumber != null ? !phoneNumber.equals(that.phoneNumber) : that.phoneNumber != null)
+            return false;
+
+        if (hireDate != null ? !hireDate.equals(that.hireDate) : that.hireDate != null)
+            return false;
+
+        if (job != null ? !job.equals(that.job) : that.job != null)
+            return false;
+
+        if (salary != null ? !salary.equals(that.salary) : that.salary != null)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + departmentId;
+
+        res = 31 * res + (managerId != null ? managerId.hashCode() : 0);
+
+        res = 31 * res + (firstName != null ? firstName.hashCode() : 0);
+
+        res = 31 * res + (lastName != null ? lastName.hashCode() : 0);
+
+        res = 31 * res + (email != null ? email.hashCode() : 0);
+
+        res = 31 * res + (phoneNumber != null ? phoneNumber.hashCode() : 0);
+
+        res = 31 * res + (hireDate != null ? hireDate.hashCode() : 0);
+
+        res = 31 * res + (job != null ? job.hashCode() : 0);
+
+        res = 31 * res + (salary != null ? salary.hashCode() : 0);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Employee [id=" + id +
+            ", departmentId=" + departmentId +
+            ", managerId=" + managerId +
+            ", firstName=" + firstName +
+            ", lastName=" + lastName +
+            ", email=" + email +
+            ", phoneNumber=" + phoneNumber +
+            ", hireDate=" + hireDate +
+            ", job=" + job +
+            ", salary=" + salary +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
new file mode 100644
index 0000000..d55ae81
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Parking definition.
+ */
+public class Parking implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for name. */
+    private String name;
+
+    /** Value for capacity. */
+    private int capacity;
+
+    /**
+     * Empty constructor.
+     */
+    public Parking() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Parking(
+        int id,
+        String name,
+        int capacity
+    ) {
+        this.id = id;
+        this.name = name;
+        this.capacity = capacity;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Gets capacity.
+     *
+     * @return Value for capacity.
+     */
+    public int getCapacity() {
+        return capacity;
+    }
+
+    /**
+     * Sets capacity.
+     *
+     * @param capacity New value for capacity.
+     */
+    public void setCapacity(int capacity) {
+        this.capacity = capacity;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Parking))
+            return false;
+
+        Parking that = (Parking)o;
+
+        if (id != that.id)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        if (capacity != that.capacity)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        res = 31 * res + capacity;
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Parking [id=" + id +
+            ", name=" + name +
+            ", capacity=" + capacity +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/resources/log4j.properties b/modules/web-console/web-agent/src/main/resources/log4j.properties
new file mode 100644
index 0000000..3b7767c
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/resources/log4j.properties
@@ -0,0 +1,53 @@
+# 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.
+
+log4j.rootLogger=INFO,console_err,file
+
+log4j.logger.org.apache.http=WARN
+log4j.logger.org.apache.ignite.spi.checkpoint.noop.NoopCheckpointSpi=OFF
+log4j.logger.org.apache.ignite.spi.swapspace.noop.NoopSwapSpaceSpi=OFF
+log4j.logger.org.apache.ignite.internal.managers.collision.GridCollisionManager=ERROR
+log4j.logger.org.apache.commons.beanutils=WARN
+log4j.logger.sun.net.www.protocol.http=WARN
+
+# Configure console appender.
+log4j.appender.console_err=org.apache.log4j.ConsoleAppender
+log4j.appender.console_err.Threshold=WARN
+log4j.appender.console_err.layout=org.apache.log4j.PatternLayout
+log4j.appender.console_err.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n
+
+# Configure console appender.
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n
+log4j.appender.console.filter.a=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.console.filter.a.LevelToMatch=INFO
+log4j.appender.console.filter.a.AcceptOnMatch=true
+log4j.appender.console.filter.b=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.console.filter.b.LevelToMatch=ERROR
+log4j.appender.console.filter.b.AcceptOnMatch=false
+log4j.appender.console.filter.c=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.console.filter.c.LevelToMatch=WARN
+log4j.appender.console.filter.c.AcceptOnMatch=false
+
+log4j.category.org.apache.ignite.console=INFO,console
+
+# Direct log messages to a log file
+log4j.appender.file=org.apache.log4j.RollingFileAppender
+log4j.appender.file.File=logs/ignite-web-agent.log
+log4j.appender.file.MaxFileSize=10MB
+log4j.appender.file.MaxBackupIndex=10
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2c7bad1..070b5c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -798,8 +798,8 @@
         <profile>
             <id>web-console</id>
             <modules>
-                <module>modules/web-agent</module>
                 <module>modules/web-console</module>
+                <module>modules/web-console/web-agent</module>
                 <module>modules/schema-import-db</module>
             </modules>
         </profile>


Mime
View raw message