http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java new file mode 100644 index 0000000..02146d9 --- /dev/null +++ b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java @@ -0,0 +1,298 @@ +/* + * 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 io.socket.emitter.Emitter; +import java.io.BufferedReader; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import org.apache.ignite.console.agent.AgentConfiguration; +import org.apache.ignite.console.demo.AgentMetadataDemo; +import org.apache.ignite.schema.parser.DbMetadataReader; +import org.apache.ignite.schema.parser.DbTable; +import org.apache.log4j.Logger; + +import static org.apache.ignite.console.agent.AgentUtils.resolvePath; + +/** + * API to extract database metadata. + */ +public class DatabaseHandler { + /** */ + private static final Logger log = Logger.getLogger(DatabaseHandler.class.getName()); + + /** */ + private final File driversFolder; + + /** + * @param cfg Config. + */ + public DatabaseHandler(AgentConfiguration cfg) { + driversFolder = resolvePath(cfg.driversFolder() == null ? "jdbc-drivers" : cfg.driversFolder()); + } + + /** + * @param jdbcDriverJarPath JDBC driver JAR path. + * @param jdbcDriverCls JDBC driver class. + * @param jdbcUrl JDBC URL. + * @param jdbcInfo Properties to connect to database. + * @return Connection to database. + * @throws SQLException + */ + private Connection connect(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl, + Properties jdbcInfo) throws SQLException { + if (AgentMetadataDemo.isTestDriveUrl(jdbcUrl)) + return AgentMetadataDemo.testDrive(); + + if (!new File(jdbcDriverJarPath).isAbsolute() && driversFolder != null) + jdbcDriverJarPath = new File(driversFolder, jdbcDriverJarPath).getPath(); + + return DbMetadataReader.getInstance().connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo); + } + + /** + * @param jdbcDriverJarPath JDBC driver JAR path. + * @param jdbcDriverCls JDBC driver class. + * @param jdbcUrl JDBC URL. + * @param jdbcInfo Properties to connect to database. + * @return Collection of schema names. + * @throws SQLException + */ + protected Collection<String> schemas(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl, + Properties jdbcInfo) throws SQLException { + if (log.isDebugEnabled()) + log.debug("Start collecting database schemas [drvJar=" + jdbcDriverJarPath + + ", drvCls=" + jdbcDriverCls + ", jdbcUrl=" + jdbcUrl + "]"); + + try (Connection conn = connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo)) { + Collection<String> schemas = DbMetadataReader.getInstance().schemas(conn); + + if (log.isDebugEnabled()) + log.debug("Finished collection of schemas [jdbcUrl=" + jdbcUrl + ", count=" + schemas.size() + "]"); + + return schemas; + } + catch (Throwable e) { + log.error("Failed to collect schemas", e); + + throw new SQLException("Failed to collect schemas", e); + } + } + + /** + * Listener for schema names. + * + * @return Collection of schema names. + */ + public Emitter.Listener schemasListener() { + return new AbstractHandler() { + @Override public Object execute(Map<String, Object> args) throws Exception { + String driverPath = null; + + if (args.containsKey("driverPath")) + driverPath = args.get("driverPath").toString(); + + if (!args.containsKey("driverClass")) + throw new IllegalArgumentException("Missing driverClass in arguments: " + args); + + String driverCls = args.get("driverClass").toString(); + + if (!args.containsKey("url")) + throw new IllegalArgumentException("Missing url in arguments: " + args); + + String url = args.get("url").toString(); + + if (!args.containsKey("info")) + throw new IllegalArgumentException("Missing info in arguments: " + args); + + Properties info = new Properties(); + + info.putAll((Map)args.get("info")); + + return schemas(driverPath, driverCls, url, info); + } + }; + } + + /** + * @param jdbcDriverJarPath JDBC driver JAR path. + * @param jdbcDriverCls JDBC driver class. + * @param jdbcUrl JDBC URL. + * @param jdbcInfo Properties to connect to database. + * @param schemas List of schema names to process. + * @param tblsOnly If {@code true} then only tables will be processed otherwise views also will be processed. + * @return Collection of tables. + */ + protected Collection<DbTable> metadata(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl, + Properties jdbcInfo, List<String> schemas, boolean tblsOnly) throws SQLException { + if (log.isDebugEnabled()) + log.debug("Start collecting database metadata [drvJar=" + jdbcDriverJarPath + + ", drvCls=" + jdbcDriverCls + ", jdbcUrl=" + jdbcUrl + "]"); + + try (Connection conn = connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo)) { + Collection<DbTable> metadata = DbMetadataReader.getInstance().metadata(conn, schemas, tblsOnly); + + if (log.isDebugEnabled()) + log.debug("Finished collection of metadata [jdbcUrl=" + jdbcUrl + ", count=" + metadata.size() + "]"); + + return metadata; + } + catch (Throwable e) { + log.error("Failed to collect metadata", e); + + throw new SQLException("Failed to collect metadata", e); + } + } + + /** + * Listener for tables. + * + * @return Collection of tables. + */ + public Emitter.Listener metadataListener() { + return new AbstractHandler() { + @SuppressWarnings("unchecked") + @Override public Object execute(Map<String, Object> args) throws Exception { + String driverPath = null; + + if (args.containsKey("driverPath")) + driverPath = args.get("driverPath").toString(); + + if (!args.containsKey("driverClass")) + throw new IllegalArgumentException("Missing driverClass in arguments: " + args); + + String driverCls = args.get("driverClass").toString(); + + if (!args.containsKey("url")) + throw new IllegalArgumentException("Missing url in arguments: " + args); + + String url = args.get("url").toString(); + + if (!args.containsKey("info")) + throw new IllegalArgumentException("Missing info in arguments: " + args); + + Properties info = new Properties(); + + info.putAll((Map)args.get("info")); + + if (!args.containsKey("schemas")) + throw new IllegalArgumentException("Missing schemas in arguments: " + args); + + List<String> schemas = (List<String>)args.get("schemas"); + + if (!args.containsKey("tablesOnly")) + throw new IllegalArgumentException("Missing tablesOnly in arguments: " + args); + + boolean tblsOnly = (boolean)args.get("tablesOnly"); + + return metadata(driverPath, driverCls, url, info, schemas, tblsOnly); + } + }; + } + + /** + * Listener for drivers. + * + * @return Drivers in drivers folder + * @see AgentConfiguration#driversFolder + */ + public Emitter.Listener availableDriversListener() { + return new AbstractHandler() { + @Override public Object execute(Map<String, Object> args) throws Exception { + if (driversFolder == null) { + log.info("JDBC drivers folder not specified, returning empty list"); + + return Collections.emptyList(); + } + + if (log.isDebugEnabled()) + log.debug("Collecting JDBC drivers in folder: " + driversFolder.getPath()); + + File[] list = driversFolder.listFiles(new FilenameFilter() { + @Override public boolean accept(File dir, String name) { + return name.endsWith(".jar"); + } + }); + + if (list == null) { + log.info("JDBC drivers folder has no files, returning empty list"); + + return Collections.emptyList(); + } + + List<JdbcDriver> res = new ArrayList<>(); + + for (File file : list) { + try { + boolean win = System.getProperty("os.name").contains("win"); + + URL url = new URL("jar", null, + "file:" + (win ? "/" : "") + file.getPath() + "!/META-INF/services/java.sql.Driver"); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) { + String jdbcDriverCls = reader.readLine(); + + res.add(new JdbcDriver(file.getName(), jdbcDriverCls)); + + if (log.isDebugEnabled()) + log.debug("Found: [driver=" + file + ", class=" + jdbcDriverCls + "]"); + } + } + catch (IOException e) { + res.add(new JdbcDriver(file.getName(), null)); + + log.info("Found: [driver=" + file + "]"); + log.info("Failed to detect driver class: " + e.getMessage()); + } + } + + return res; + } + }; + } + + /** + * Wrapper class for later to be transformed to JSON and send to Web Console. + */ + private static class JdbcDriver { + /** */ + public final String jdbcDriverJar; + /** */ + public final String jdbcDriverCls; + + /** + * @param jdbcDriverJar File name of driver jar file. + * @param jdbcDriverCls Optional JDBC driver class. + */ + public JdbcDriver(String jdbcDriverJar, String jdbcDriverCls) { + this.jdbcDriverJar = jdbcDriverJar; + this.jdbcDriverCls = jdbcDriverCls; + } + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java b/modules/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-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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java new file mode 100644 index 0000000..d09e5c7 --- /dev/null +++ b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java @@ -0,0 +1,614 @@ +/* + * 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.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Random; +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.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_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 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); + else + cfg.setCacheConfiguration(cacheCountry(), cacheDepartment(), cacheEmployee(), cacheParking(), cacheCar()); + + 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 { + IgniteCache<Integer, Employee> cacheEmployee = ignite.cache(EMPLOYEE_CACHE_NAME); + + if (cacheEmployee == null) + return; + + 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_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 test-drive successfully started"); + + startLoad(ignite, 20); + } + catch (Exception e) { + log.error("DEMO: Failed to start embedded node for sql test-drive!", e); + + return false; + } + } + + return true; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java new file mode 100644 index 0000000..4683dd8 --- /dev/null +++ b/modules/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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java b/modules/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-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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java b/modules/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-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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java b/modules/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-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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java b/modules/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-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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java b/modules/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-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/eb5ac0ae/modules/web-agent/src/main/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/resources/log4j.properties b/modules/web-agent/src/main/resources/log4j.properties new file mode 100644 index 0000000..3b7767c --- /dev/null +++ b/modules/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/eb5ac0ae/modules/web-console/DEVNOTES.txt ---------------------------------------------------------------------- diff --git a/modules/web-console/DEVNOTES.txt b/modules/web-console/DEVNOTES.txt new file mode 100644 index 0000000..4acc6ef --- /dev/null +++ b/modules/web-console/DEVNOTES.txt @@ -0,0 +1,28 @@ +Ignite Web Console Instructions +====================================== + +How to deploy locally: + +1. Install locally MongoDB (version >=3.x) follow instructions from site http://docs.mongodb.org/manual/installation +2. Install locally NodeJS (version >=4.x) using installer from site https://nodejs.org for your OS. +3. Checkout ignite-1.6 branch. +4. Change directory '$IGNITE_HOME/modules/web-console/src/main/js'. +5. Run "npm install" in terminal for download all dependencies. +6. Build ignite-web-agent module follow instructions from 'modules/web-agent/README.txt'. +7. Copy ignite-web-agent-<version>.zip from target of ignite-web-agent module to 'modules/web-console/src/main/js/public/agent' folder. + +Steps 1 - 7 should be executed once. + +How to run console in development mode: + +1. Configure MongoDB to run as service or in terminal change dir to $MONGO_INSTALL_DIR/server/3.0/bin + and start MongoDB by executing "mongod". + +2. In new terminal change directory '$IGNITE_HOME/modules/web-console/src/main/js' + and start application by executing "npm start" (for first time) or "node serve" to start backend. + +3. In new terminal change directory '$IGNITE_HOME/modules/web-console/src/main/js' + and start virtual server and local changes watcher by executing "gulp watch --debug" + or "gulp connect" to start web server only. + +4. In browser open: http://localhost:8090 http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-console/README.txt ---------------------------------------------------------------------- diff --git a/modules/web-console/README.txt b/modules/web-console/README.txt new file mode 100644 index 0000000..ae509d6 --- /dev/null +++ b/modules/web-console/README.txt @@ -0,0 +1,36 @@ +Ignite Web Console +====================================== +An Interactive Configuration Wizard and Management Tool for Apache Ignite + +The Apache Ignite Web Console includes an interactive configuration wizard which helps you create and download configuration + files for your Apache Ignite cluster. The tool also provides management capabilities which allow you to run SQL queries + on your in-memory cache as well as view execution plans, in-memory schema, and streaming charts. + +In order to simplify evaluation of Web Console demo mode was implemented. + To start demo, you need to to click button "Start demo". New tab will be open with prepared demo data on each screen. + + Demo for import domain model from database. + In this mode an in-memory H2 database will be started. + How to evaluate: + 1) Go to Ignite Web Console "Domain model" screen. + 2) Click "Import from database". You should see modal with demo description. + 3) Click "Next" button. You should see list of available schemas. + 4) Click "Next" button. You should see list of available tables. + 5) Click "Next" button. You should see import options. + 6) Select some of them and click "Save". + + Demo for SQL. + How to evaluate: + In this mode internal Ignite node will be started. Cache created and populated with data. + 1) Click "SQL" in Ignite Web Console top menu. + 2) "Demo" notebook with preconfigured queries will be opened. + 3) You can also execute any SQL queries for tables: "Country, Department, Employee", "Parking, Car". + + For example: + 1) Enter SQL statement: + SELECT p.name, count(*) AS cnt FROM "ParkingCache".Parking p + INNER JOIN "CarCache".Car c ON (p.id) = (c.parkingId) + GROUP BY P.NAME + 2) Click "Execute" button. You should get some data in table. + 3) Click charts buttons to see auto generated charts. +
