You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2016/09/09 03:26:30 UTC
[02/52] ignite git commit: Web Console beta-3.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/getting-started.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/getting-started.jade b/modules/web-console/src/main/js/views/templates/getting-started.jade
deleted file mode 100644
index 98bc265..0000000
--- a/modules/web-console/src/main/js/views/templates/getting-started.jade
+++ /dev/null
@@ -1,32 +0,0 @@
-//-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-.modal.center(role='dialog')
- .modal-dialog
- .modal-content
- #errors-container.modal-header.header
- button.close(ng-click='close()' aria-hidden='true') ×
- h4.modal-title {{title}}
- .getting-started
- .col-xs-12(ng-bind-html='message')
- .modal-footer
- .checkbox
- label
- input(type='checkbox' ng-model='ui.showGettingStarted')
- | Show getting started on next login
- a.btn.btn-primary(ng-disabled='isFirst()' ng-click='!isFirst() && prev()') Prev
- a.btn.btn-primary(ng-disabled='isLast()' ng-click='!isLast() && next()') Next
- a.btn.btn-primary(ng-click='close()') Close
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/message.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/message.jade b/modules/web-console/src/main/js/views/templates/message.jade
deleted file mode 100644
index 6dcf445..0000000
--- a/modules/web-console/src/main/js/views/templates/message.jade
+++ /dev/null
@@ -1,26 +0,0 @@
-//-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-.modal(tabindex='-1' role='dialog')
- .modal-dialog
- .modal-content
- .modal-header
- button.close(ng-click='$hide()' aria-hidden='true') ×
- h4.modal-title {{title}}
- .modal-body(ng-show='content')
- p(ng-bind-html='content.join("<br/>")' style='text-align: left;')
- .modal-footer
- button.btn.btn-primary(id='confirm-btn-confirm' ng-click='$hide()') Ok
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/pagination.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/pagination.jade b/modules/web-console/src/main/js/views/templates/pagination.jade
deleted file mode 100644
index 08ced60..0000000
--- a/modules/web-console/src/main/js/views/templates/pagination.jade
+++ /dev/null
@@ -1,32 +0,0 @@
-//-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-nav(ng-if='numPages && pages.length >= 2')
- ul.pagination
- li(ng-if='currentPage > 1')
- a(href='javascript:void(0);' ng-click='selectPage(1)' bs-tooltip='' data-title='First page' data-placement='bottom')
- i.fa.fa-angle-double-left
- li(ng-if='currentPage > 1')
- a(href='javascript:void(0);' ng-click='selectPage(currentPage-1)' bs-tooltip='' data-title='Previous page' data-placement='bottom')
- i.fa.fa-angle-left
- li(ng-repeat='page in pages' ng-class='{active: page==currentPage}')
- a(href='javascript:void(0);' ng-click='selectPage(page)') {{page}}
- li(ng-if='currentPage < numPages')
- a(href='javascript:void(0);' ng-click='selectPage(currentPage+1)' bs-tooltip='' data-title='Next page' data-placement='bottom')
- i.fa.fa-angle-right
- li(ng-if='currentPage < numPages')
- a(href='javascript:void(0);' ng-click='selectPage(numPages)' bs-tooltip='' data-title='Last page' data-placement='bottom')
- i.fa.fa-angle-double-right
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/select.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/select.jade b/modules/web-console/src/main/js/views/templates/select.jade
deleted file mode 100644
index 3feee61..0000000
--- a/modules/web-console/src/main/js/views/templates/select.jade
+++ /dev/null
@@ -1,26 +0,0 @@
-//-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-ul.select.dropdown-menu(tabindex='-1' ng-show='$isVisible()' role='select')
- li(ng-if='$showAllNoneButtons || ($isMultiple && $matches.length > 2)')
- a(id='li-dropdown-select-all' ng-click='$selectAll()') {{$allText}} ({{$matches.length}})
- a(id='li-dropdown-select-none' ng-click='$selectNone()') {{$noneText}}
- hr(style='margin: 5px 0')
- li(role='presentation' ng-repeat='match in $matches')
- hr(ng-if='match.value == undefined' style='margin: 5px 0')
- a(id='li-dropdown-item-{{$index}}' role='menuitem' tabindex='-1' ng-class='{active: $isActive($index)}' ng-click='$select($index, $event)' bs-tooltip='widthIsSufficient && !widthIsSufficient("li-dropdown-item-{{$index}}", $index, match.label) ? match.label : ""' data-placement='bottom')
- i(class='{{$iconCheckmark}}' ng-if='$isActive($index)' ng-class='{active: $isActive($index)}')
- span(ng-bind='match.label')
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/validation-error.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/validation-error.jade b/modules/web-console/src/main/js/views/templates/validation-error.jade
deleted file mode 100644
index 13deb9b..0000000
--- a/modules/web-console/src/main/js/views/templates/validation-error.jade
+++ /dev/null
@@ -1,25 +0,0 @@
-//-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-.popover.validation-error
- .arrow
- .popover-content
- table
- tr
- td
- label {{content}}  
- td
- button.close(id='popover-btn-close' ng-click='$hide()') ×
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/test/js/routes/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/test/js/routes/agent.js b/modules/web-console/src/test/js/routes/agent.js
deleted file mode 100644
index 1c4aff5..0000000
--- a/modules/web-console/src/test/js/routes/agent.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var request = require('supertest'),
- should = require('should'),
- app = require('../../app'),
- fs = require('fs'),
- https = require('https'),
- config = require('../../helpers/configuration-loader.js'),
- agentManager = require('../../agents/agent-manager');
-
-/**
- * Create HTTP server.
- */
-/**
- * Start agent server.
- */
-var agentServer = https.createServer({
- key: fs.readFileSync(config.get('monitor:server:key')),
- cert: fs.readFileSync(config.get('monitor:server:cert')),
- passphrase: config.get('monitor:server:keyPassphrase')
-});
-
-agentServer.listen(config.get('monitor:server:port'));
-
-agentManager.createManager(agentServer);
-
-describe('request from agent', function() {
- var agent = request.agent(app);
-
- before(function (done) {
- this.timeout(10000);
-
- agent
- .post('/login')
- .send({email: 'test@test.com', password: 'test'})
- .expect(302)
- .end(function (err) {
- if (error)
- throw error;
-
- setTimeout(done, 5000);
- });
- });
-
- it('should return topology snapshot', function(done){
- agent
- .post('/agent/topology')
- .send({})
- .end(function(err, nodes) {
- if (error) {
- console.log(error.response.text);
-
- throw error;
- }
-
- console.log(nodes);
-
- done();
- });
- });
-
- //it('should query result', function(done){
- // agent
- // .post('/agent/query')
- // .send({
- // username: 'nva',
- // password: 'nva.141',
- // host: 'localhost',
- // port: '5432',
- // dbName: 'ggmonitor'
- // })
- // .end(function(err, res) {
- // if (err)
- // throw err;
- //
- // done();
- // });
- //});
-});
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/.gitignore b/modules/web-console/web-agent/.gitignore
new file mode 100644
index 0000000..57dd45e
--- /dev/null
+++ b/modules/web-console/web-agent/.gitignore
@@ -0,0 +1,2 @@
+logs/*.log.*
+jdbc-drivers/*.jar
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/README.txt b/modules/web-console/web-agent/README.txt
new file mode 100644
index 0000000..c6e625b
--- /dev/null
+++ b/modules/web-console/web-agent/README.txt
@@ -0,0 +1,88 @@
+Ignite Web Agent
+======================================
+Ignite Web Agent is a java standalone application that allow to connect Ignite Grid to Ignite Web Console.
+Ignite Web Agent communicates with grid nodes via REST interface and connects to Ignite Web Console via web-socket.
+
+Two main functions of Ignite Web Agent:
+ 1. Proxy between Ignite Web Console and Ignite Grid to execute SQL statements and collect metrics for monitoring.
+ You may need to specify URI for connect to Ignite REST server via "-n" option.
+
+ 2. Proxy between Ignite Web Console and user RDBMS to collect database metadata for later CacheTypeMetadata configuration.
+ You may need to copy JDBC driver into "./jdbc-drivers" subfolder or specify path via "-d" option.
+
+Usage example:
+ ignite-web-agent.sh
+
+Configuration file:
+ Should be a file with simple line-oriented format as described here: http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load(java.io.Reader)
+
+ Available entries names:
+ tokens
+ server-uri
+ node-uri
+ driver-folder
+
+ Example configuration file:
+ tokens=1a2b3c4d5f,2j1s134d12
+ serverURI=https://console.example.com:3001
+
+Security tokens:
+ 1) By default security token of current user will be included into "default.properties" inside downloaded "ignite-web-agent-x.x.x.zip".
+ 2) One can get/reset token in Web Console profile (https://<your_console_address>/settings/profile).
+ 3) One may specify several comma separated tokens using configuration file or command line arguments of web agent.
+
+Ignite Web agent requirements:
+ 1) In order to communicate with web agent Ignite node should be started with REST server (move ignite-rest-http folder from lib/optional/ to lib/).
+ 2) Configure web agent serverURI property by Ignite node REST server URI.
+
+Options:
+ -h, --help
+ Print this help message
+ -c, --config
+ Path to configuration file
+ -d, --driver-folder
+ Path to folder with JDBC drivers, default value: ./jdbc-drivers
+ -n, --node-uri
+ URI for connect to Ignite REST server, default value:
+ http://localhost:8080
+ -s, --server-uri
+ URI for connect to Ignite Web Console via web-socket protocol, default
+ value: http://localhost:3001
+ -t, --tokens
+ User's security tokens
+
+How to build:
+ To build from sources run following command in Ignite project root folder:
+ mvn clean package -pl :ignite-web-agent -am -P web-console -DskipTests=true
+
+Demo of Ignite Web Agent:
+ In order to simplify evaluation demo mode was implemented. To start demo, you need to click button "Start demo".
+ New tab will be open with prepared demo data.
+
+ 1) Demo for import domain model from database.
+ In this mode an in-memory H2 database will be started.
+ How to evaluate:
+ 1.1) Go to Ignite Web Console "Domain model" screen.
+ 1.2) Click "Import from database". You should see modal with demo description.
+ 1.3) Click "Next" button. You should see list of available schemas.
+ 1.4) Click "Next" button. You should see list of available tables.
+ 1.5) Click "Next" button. You should see import options.
+ 1.6) Select some of them and click "Save".
+
+ 2) Demo for SQL.
+ How to evaluate:
+ In this mode internal Ignite node will be started. Cache created and populated with data.
+ 2.1) Click "SQL" in Ignite Web Console top menu.
+ 2.2) "Demo" notebook with preconfigured queries will be opened.
+ 2.3) You can also execute any SQL queries for tables: "Country, Department, Employee, Parking, Car".
+
+ For example:
+ 2.4) 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.5) Click "Execute" button. You should get some data in table.
+ 2.6) Click charts buttons to see auto generated charts.
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/assembly/release-web-agent.xml
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/assembly/release-web-agent.xml b/modules/web-console/web-agent/assembly/release-web-agent.xml
new file mode 100644
index 0000000..bb994c0
--- /dev/null
+++ b/modules/web-console/web-agent/assembly/release-web-agent.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+ <id>release-ignite-web-agent</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <fileSets>
+ <fileSet>
+ <directory>${basedir}</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>jdbc-drivers/README*</include>
+ <include>demo/README*</include>
+ <include>demo/*.sql</include>
+ <include>logs/README*</include>
+ <include>README*</include>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${basedir}/bin</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>**/*.bat</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${basedir}/bin</directory>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>0755</fileMode>
+ <includes>
+ <include>**/*.sh</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>ignite-web-agent-${project.version}.jar</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/bin/ignite-web-agent.bat
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/bin/ignite-web-agent.bat b/modules/web-console/web-agent/bin/ignite-web-agent.bat
new file mode 100644
index 0000000..f16eb35
--- /dev/null
+++ b/modules/web-console/web-agent/bin/ignite-web-agent.bat
@@ -0,0 +1,70 @@
+::
+:: 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.
+::
+
+@echo off
+Setlocal EnableDelayedExpansion
+
+if "%OS%" == "Windows_NT" setlocal
+
+:: Check JAVA_HOME.
+if defined JAVA_HOME goto checkJdk
+ echo %0, ERROR:
+ echo JAVA_HOME environment variable is not found.
+ echo Please point JAVA_HOME variable to location of JDK 1.7 or JDK 1.8.
+ echo You can also download latest JDK at http://java.com/download.
+goto error_finish
+
+:checkJdk
+:: Check that JDK is where it should be.
+if exist "%JAVA_HOME%\bin\java.exe" goto checkJdkVersion
+ echo %0, ERROR:
+ echo JAVA is not found in JAVA_HOME=%JAVA_HOME%.
+ echo Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8.
+ echo You can also download latest JDK at http://java.com/download.
+goto error_finish
+
+:checkJdkVersion
+"%JAVA_HOME%\bin\java.exe" -version 2>&1 | findstr "1\.[78]\." > nul
+if %ERRORLEVEL% equ 0 goto run_java
+ echo %0, ERROR:
+ echo The version of JAVA installed in %JAVA_HOME% is incorrect.
+ echo Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8.
+ echo You can also download latest JDK at http://java.com/download.
+goto error_finish
+
+:run_java
+
+::
+:: JVM options. See http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp for more details.
+::
+:: ADD YOUR/CHANGE ADDITIONAL OPTIONS HERE
+::
+if "%JVM_OPTS%" == "" set JVM_OPTS=-Xms1g -Xmx1g -server -XX:+AggressiveOpts -XX:MaxPermSize=256m
+
+"%JAVA_HOME%\bin\java.exe" %JVM_OPTS% -cp "*" org.apache.ignite.console.agent.AgentLauncher %*
+
+set JAVA_ERRORLEVEL=%ERRORLEVEL%
+
+:: errorlevel 130 if aborted with Ctrl+c
+if %JAVA_ERRORLEVEL%==130 goto eof
+
+:error_finish
+
+if not "%NO_PAUSE%" == "1" pause
+
+goto :eof
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/bin/ignite-web-agent.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/bin/ignite-web-agent.sh b/modules/web-console/web-agent/bin/ignite-web-agent.sh
new file mode 100644
index 0000000..3f2c2bc
--- /dev/null
+++ b/modules/web-console/web-agent/bin/ignite-web-agent.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+#
+# 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.
+#
+
+# Check JAVA_HOME.
+if [ "$JAVA_HOME" = "" ]; then
+ JAVA=`type -p java`
+ RETCODE=$?
+
+ if [ $RETCODE -ne 0 ]; then
+ echo $0", ERROR:"
+ echo "JAVA_HOME environment variable is not found."
+ echo "Please point JAVA_HOME variable to location of JDK 1.7 or JDK 1.8."
+ echo "You can also download latest JDK at http://java.com/download"
+
+ exit 1
+ fi
+
+ JAVA_HOME=
+else
+ JAVA=${JAVA_HOME}/bin/java
+fi
+
+#
+# Check JDK.
+#
+if [ ! -e "$JAVA" ]; then
+ echo $0", ERROR:"
+ echo "JAVA is not found in JAVA_HOME=$JAVA_HOME."
+ echo "Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8."
+ echo "You can also download latest JDK at http://java.com/download"
+
+ exit 1
+fi
+
+JAVA_VER=`"$JAVA" -version 2>&1 | egrep "1\.[78]\."`
+
+if [ "$JAVA_VER" == "" ]; then
+ echo $0", ERROR:"
+ echo "The version of JAVA installed in JAVA_HOME=$JAVA_HOME is incorrect."
+ echo "Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8."
+ echo "You can also download latest JDK at http://java.com/download"
+
+ exit 1
+fi
+
+SOURCE="${BASH_SOURCE[0]}"
+
+DIR="$( dirname "$SOURCE" )"
+
+while [ -h "$SOURCE" ]
+ do
+ SOURCE="$(readlink "$SOURCE")"
+
+ [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
+
+ DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
+ done
+
+DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
+
+cd $DIR
+
+#
+# JVM options. See http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp for more details.
+#
+# ADD YOUR/CHANGE ADDITIONAL OPTIONS HERE
+#
+if [ -z "$JVM_OPTS" ] ; then
+ JVM_OPTS="-Xms1g -Xmx1g -server -XX:+AggressiveOpts -XX:MaxPermSize=256m"
+fi
+
+"$JAVA" ${JVM_OPTS} -cp "*" org.apache.ignite.console.agent.AgentLauncher "$@"
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/demo/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/demo/README.txt b/modules/web-console/web-agent/demo/README.txt
new file mode 100644
index 0000000..17e5074
--- /dev/null
+++ b/modules/web-console/web-agent/demo/README.txt
@@ -0,0 +1,4 @@
+Ignite Web Agent
+======================================
+
+This is folder for demo files.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/demo/db-init.sql
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/demo/db-init.sql b/modules/web-console/web-agent/demo/db-init.sql
new file mode 100644
index 0000000..0688ea0
--- /dev/null
+++ b/modules/web-console/web-agent/demo/db-init.sql
@@ -0,0 +1,102 @@
+--
+-- 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.
+--
+
+CREATE TABLE COUNTRY (
+ ID INTEGER NOT NULL PRIMARY KEY,
+ NAME VARCHAR(50),
+ POPULATION INTEGER NOT NULL
+);
+
+CREATE TABLE DEPARTMENT (
+ ID INTEGER NOT NULL PRIMARY KEY,
+ COUNTRY_ID INTEGER NOT NULL,
+ NAME VARCHAR(50) NOT NULL
+);
+
+CREATE TABLE EMPLOYEE (
+ ID INTEGER NOT NULL PRIMARY KEY,
+ DEPARTMENT_ID INTEGER NOT NULL,
+ MANAGER_ID INTEGER,
+ FIRST_NAME VARCHAR(50) NOT NULL,
+ LAST_NAME VARCHAR(50) NOT NULL,
+ EMAIL VARCHAR(50) NOT NULL,
+ PHONE_NUMBER VARCHAR(50),
+ HIRE_DATE DATE NOT NULL,
+ JOB VARCHAR(50) NOT NULL,
+ SALARY DOUBLE
+);
+
+CREATE INDEX EMP_SALARY ON EMPLOYEE (SALARY ASC);
+CREATE INDEX EMP_NAMES ON EMPLOYEE (FIRST_NAME ASC, LAST_NAME ASC);
+
+CREATE SCHEMA CARS;
+
+CREATE TABLE CARS.PARKING (
+ ID INTEGER NOT NULL PRIMARY KEY,
+ NAME VARCHAR(50) NOT NULL,
+ CAPACITY INTEGER NOT NULL
+);
+
+CREATE TABLE CARS.CAR (
+ ID INTEGER NOT NULL PRIMARY KEY,
+ PARKING_ID INTEGER NOT NULL,
+ NAME VARCHAR(50) NOT NULL
+);
+
+INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(0, 'Country #1', 10000000);
+INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(1, 'Country #2', 20000000);
+INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(2, 'Country #3', 30000000);
+
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(0, 0, 'Department #1');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(1, 0, 'Department #2');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(2, 2, 'Department #3');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(3, 1, 'Department #4');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(4, 1, 'Department #5');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(5, 1, 'Department #6');
+
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(0, 0, 'First name manager #1', 'Last name manager #1', 'Email manager #1', 'Phone number manager #1', '2014-01-01', 'Job manager #1', 1100.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(1, 1, 'First name manager #2', 'Last name manager #2', 'Email manager #2', 'Phone number manager #2', '2014-01-01', 'Job manager #2', 2100.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(2, 2, 'First name manager #3', 'Last name manager #3', 'Email manager #3', 'Phone number manager #3', '2014-01-01', 'Job manager #3', 3100.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(3, 3, 'First name manager #4', 'Last name manager #4', 'Email manager #4', 'Phone number manager #4', '2014-01-01', 'Job manager #4', 1500.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(4, 4, 'First name manager #5', 'Last name manager #5', 'Email manager #5', 'Phone number manager #5', '2014-01-01', 'Job manager #5', 1700.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(5, 5, 'First name manager #6', 'Last name manager #6', 'Email manager #6', 'Phone number manager #6', '2014-01-01', 'Job manager #6', 1300.00);
+
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(101, 0, 0, 'First name employee #1', 'Last name employee #1', 'Email employee #1', 'Phone number employee #1', '2014-01-01', 'Job employee #1', 600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(102, 0, 0, 'First name employee #2', 'Last name employee #2', 'Email employee #2', 'Phone number employee #2', '2014-01-01', 'Job employee #2', 1600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(103, 1, 1, 'First name employee #3', 'Last name employee #3', 'Email employee #3', 'Phone number employee #3', '2014-01-01', 'Job employee #3', 2600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(104, 2, 2, 'First name employee #4', 'Last name employee #4', 'Email employee #4', 'Phone number employee #4', '2014-01-01', 'Job employee #4', 1000.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(105, 2, 2, 'First name employee #5', 'Last name employee #5', 'Email employee #5', 'Phone number employee #5', '2014-01-01', 'Job employee #5', 1200.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(106, 2, 2, 'First name employee #6', 'Last name employee #6', 'Email employee #6', 'Phone number employee #6', '2014-01-01', 'Job employee #6', 800.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(107, 3, 3, 'First name employee #7', 'Last name employee #7', 'Email employee #7', 'Phone number employee #7', '2014-01-01', 'Job employee #7', 1400.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(108, 4, 4, 'First name employee #8', 'Last name employee #8', 'Email employee #8', 'Phone number employee #8', '2014-01-01', 'Job employee #8', 800.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(109, 4, 4, 'First name employee #9', 'Last name employee #9', 'Email employee #9', 'Phone number employee #9', '2014-01-01', 'Job employee #9', 1490.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(110, 4, 4, 'First name employee #10', 'Last name employee #12', 'Email employee #10', 'Phone number employee #10', '2014-01-01', 'Job employee #10', 1600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(111, 5, 5, 'First name employee #11', 'Last name employee #11', 'Email employee #11', 'Phone number employee #11', '2014-01-01', 'Job employee #11', 400.00);
+
+INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(0, 'Parking #1', 10);
+INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(1, 'Parking #2', 20);
+INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(2, 'Parking #3', 30);
+
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(0, 0, 'Car #1');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(1, 0, 'Car #2');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(2, 0, 'Car #3');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(3, 1, 'Car #4');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(4, 1, 'Car #5');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(5, 2, 'Car #6');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(6, 2, 'Car #7');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(7, 2, 'Car #8');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(8, 2, 'Car #9');
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/jdbc-drivers/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/jdbc-drivers/README.txt b/modules/web-console/web-agent/jdbc-drivers/README.txt
new file mode 100644
index 0000000..cad43b7
--- /dev/null
+++ b/modules/web-console/web-agent/jdbc-drivers/README.txt
@@ -0,0 +1,10 @@
+Ignite Web Agent
+======================================
+
+If you are are planning to load cache type metadata from your existing databases
+you need to copy JDBC drivers in this folder.
+
+This is default folder for JDBC drivers.
+
+Also, you could specify custom folder using option: "-d CUSTOM_PATH_TO_FOLDER_WITH_JDBC_DRIVERS".
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/logs/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/logs/README.txt b/modules/web-console/web-agent/logs/README.txt
new file mode 100644
index 0000000..3a220eb
--- /dev/null
+++ b/modules/web-console/web-agent/logs/README.txt
@@ -0,0 +1,5 @@
+Ignite Web Agent
+======================================
+
+This is folder for agent logs.
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/pom.xml
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/pom.xml b/modules/web-console/web-agent/pom.xml
new file mode 100644
index 0000000..530a272
--- /dev/null
+++ b/modules/web-console/web-agent/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<!--
+ POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-parent</artifactId>
+ <version>1</version>
+ <relativePath>../../../parent</relativePath>
+ </parent>
+
+ <artifactId>ignite-web-agent</artifactId>
+ <packaging>jar</packaging>
+ <version>1.7.0-SNAPSHOT</version>
+ <url>http://ignite.apache.org</url>
+
+ <properties>
+ <maven.build.timestamp.format>yyMMddHHmmss</maven.build.timestamp.format>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>io.socket</groupId>
+ <artifactId>socket.io-client</artifactId>
+ <version>0.7.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-json-org</artifactId>
+ <version>${jackson2.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.beust</groupId>
+ <artifactId>jcommander</artifactId>
+ <version>1.48</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>${httpclient.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-schema-import-db</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.gridgain</groupId>
+ <artifactId>ignite-shmem</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-indexing</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-rest-http</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-spring</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-tx</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jdbc</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-log4j</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>ignite-web-agent-${project.version}</finalName>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.5</version>
+
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>org.apache.ignite.console.agent.AgentLauncher</mainClass>
+ </manifest>
+ <manifestEntries>
+ <Build-Time>${maven.build.timestamp}</Build-Time>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.4</version>
+
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+
+ <configuration>
+ <createDependencyReducedPom>false</createDependencyReducedPom>
+ <filters>
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <exclude>META-INF/maven/**</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ <inherited>false</inherited>
+
+ <executions>
+ <execution>
+ <id>release-web-agent</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly/release-web-agent.xml</descriptor>
+ </descriptors>
+ <finalName>ignite-web-agent-${project.version}</finalName>
+ <outputDirectory>target</outputDirectory>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
new file mode 100644
index 0000000..d4787cc
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
@@ -0,0 +1,268 @@
+/*
+ * 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;
+
+import com.beust.jcommander.Parameter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Agent configuration.
+ */
+public class AgentConfiguration {
+ /** Default server port. */
+ public static final int DFLT_SERVER_PORT = 3001;
+
+ /** Default Ignite node HTTP port. */
+ public static final int DFLT_NODE_PORT = 8080;
+
+ /** Default path to agent property file. */
+ public static final String DFLT_CFG_PATH = "default.properties";
+
+ /** Default server URI. */
+ private static final String DFLT_SERVER_URI = "http://localhost:3001";
+
+ /** Default Ignite node HTTP URI. */
+ private static final String DFLT_NODE_URI = "http://localhost:8080";
+
+ /** */
+ @Parameter(names = {"-t", "--tokens"},
+ description = "User's tokens separated by comma used to connect to Ignite Console.")
+ private List<String> tokens;
+
+ /** */
+ @Parameter(names = {"-s", "--server-uri"},
+ description = "URI for connect to Ignite Console via web-socket protocol" +
+ " " +
+ " Default value: " + DFLT_SERVER_URI)
+ private String srvUri;
+
+ /** */
+ @Parameter(names = {"-n", "--node-uri"}, description = "URI for connect to Ignite node REST server" +
+ " " +
+ " Default value: " + DFLT_NODE_URI)
+ private String nodeUri;
+
+ /** URI for connect to Ignite demo node REST server */
+ private String demoNodeUri;
+
+ /** */
+ @Parameter(names = {"-c", "--config"}, description = "Path to agent property file" +
+ " " +
+ " Default value: " + DFLT_CFG_PATH)
+ private String cfgPath;
+
+ /** */
+ @Parameter(names = {"-d", "--driver-folder"}, description = "Path to folder with JDBC drivers" +
+ " " +
+ " Default value: ./jdbc-drivers")
+ private String driversFolder;
+
+ /** */
+ @Parameter(names = { "-h", "--help" }, help = true, description = "Print this help message")
+ private Boolean help;
+
+ /**
+ * @return Tokens.
+ */
+ public List<String> tokens() {
+ return tokens;
+ }
+
+ /**
+ * @param tokens Tokens.
+ */
+ public void tokens(List<String> tokens) {
+ this.tokens = tokens;
+ }
+
+ /**
+ * @return Server URI.
+ */
+ public String serverUri() {
+ return srvUri;
+ }
+
+ /**
+ * @param srvUri URI.
+ */
+ public void serverUri(String srvUri) {
+ this.srvUri = srvUri;
+ }
+
+ /**
+ * @return Node URI.
+ */
+ public String nodeUri() {
+ return nodeUri;
+ }
+
+ /**
+ * @param nodeUri Node URI.
+ */
+ public void nodeUri(String nodeUri) {
+ this.nodeUri = nodeUri;
+ }
+
+ /**
+ * @return Demo node URI.
+ */
+ public String demoNodeUri() {
+ return demoNodeUri;
+ }
+
+ /**
+ * @param demoNodeUri Demo node URI.
+ */
+ public void demoNodeUri(String demoNodeUri) {
+ this.demoNodeUri = demoNodeUri;
+ }
+
+ /**
+ * @return Configuration path.
+ */
+ public String configPath() {
+ return cfgPath == null ? DFLT_CFG_PATH : cfgPath;
+ }
+
+ /**
+ * @return Configured drivers folder.
+ */
+ public String driversFolder() {
+ return driversFolder;
+ }
+
+ /**
+ * @param driversFolder Driver folder.
+ */
+ public void driversFolder(String driversFolder) {
+ this.driversFolder = driversFolder;
+ }
+
+ /**
+ * @return {@code true} If agent options usage should be printed.
+ */
+ public Boolean help() {
+ return help != null ? help : Boolean.FALSE;
+ }
+
+ /**
+ * @param cfgUrl URL.
+ */
+ public void load(URL cfgUrl) throws IOException {
+ Properties props = new Properties();
+
+ try (Reader reader = new InputStreamReader(cfgUrl.openStream())) {
+ props.load(reader);
+ }
+
+ String val = (String)props.remove("tokens");
+
+ if (val != null)
+ tokens(Arrays.asList(val.split(",")));
+
+ val = (String)props.remove("server-uri");
+
+ if (val != null)
+ serverUri(val);
+
+ val = (String)props.remove("node-uri");
+
+ if (val != null)
+ nodeUri(val);
+
+ val = (String)props.remove("driver-folder");
+
+ if (val != null)
+ driversFolder(val);
+ }
+
+ /**
+ * @param cmd Command.
+ */
+ public void merge(AgentConfiguration cmd) {
+ if (tokens == null)
+ tokens(cmd.tokens());
+
+ if (srvUri == null)
+ serverUri(cmd.serverUri());
+
+ if (srvUri == null)
+ serverUri(DFLT_SERVER_URI);
+
+ if (nodeUri == null)
+ nodeUri(cmd.nodeUri());
+
+ if (nodeUri == null)
+ nodeUri(DFLT_NODE_URI);
+
+ if (driversFolder == null)
+ driversFolder(cmd.driversFolder());
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ if (tokens != null && tokens.size() > 0) {
+ sb.append("User's security tokens : ");
+
+ boolean first = true;
+
+ for (String tok : tokens) {
+ if (first)
+ first = false;
+ else
+ sb.append(",");
+
+ if (tok.length() > 4) {
+ sb.append(new String(new char[tok.length() - 4]).replace('\0', '*'));
+
+ sb.append(tok.substring(tok.length() - 4));
+ }
+ else
+ sb.append(new String(new char[tok.length()]).replace('\0', '*'));
+ }
+
+ sb.append('\n');
+ }
+
+ sb.append("URI to Ignite node REST server: ").append(nodeUri == null ? DFLT_NODE_URI : nodeUri).append('\n');
+ sb.append("URI to Ignite Console server : ").append(srvUri == null ? DFLT_SERVER_URI : srvUri).append('\n');
+ sb.append("Path to agent property file : ").append(configPath()).append('\n');
+
+ String drvFld = driversFolder();
+
+ if (drvFld == null) {
+ File agentHome = AgentUtils.getAgentHome();
+
+ if (agentHome != null)
+ drvFld = new File(agentHome, "jdbc-drivers").getPath();
+ }
+
+ sb.append("Path to JDBC drivers folder : ").append(drvFld);
+
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
new file mode 100644
index 0000000..810fad4
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
@@ -0,0 +1,344 @@
+/*
+ * 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;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.ParameterException;
+import io.socket.client.Ack;
+import io.socket.client.IO;
+import io.socket.client.Socket;
+import io.socket.emitter.Emitter;
+import java.io.File;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.ignite.console.agent.handlers.DatabaseHandler;
+import org.apache.ignite.console.agent.handlers.RestHandler;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.log4j.Logger;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import static io.socket.client.Socket.EVENT_CONNECT;
+import static io.socket.client.Socket.EVENT_CONNECTING;
+import static io.socket.client.Socket.EVENT_CONNECT_ERROR;
+import static io.socket.client.Socket.EVENT_DISCONNECT;
+import static io.socket.client.Socket.EVENT_ERROR;
+import static io.socket.client.Socket.EVENT_RECONNECTING;
+import static org.apache.ignite.console.agent.AgentConfiguration.DFLT_SERVER_PORT;
+
+/**
+ * Control Center Agent launcher.
+ */
+public class AgentLauncher {
+ /** */
+ private static final Logger log = Logger.getLogger(AgentLauncher.class.getName());
+
+ /** */
+ private static final String EVENT_NODE_REST = "node:rest";
+
+ /** */
+ private static final String EVENT_SCHEMA_IMPORT_DRIVERS = "schemaImport:drivers";
+
+ /** */
+ private static final String EVENT_SCHEMA_IMPORT_SCHEMAS = "schemaImport:schemas";
+
+ /** */
+ private static final String EVENT_SCHEMA_IMPORT_METADATA = "schemaImport:metadata";
+
+ /** */
+ private static final String EVENT_AGENT_WARNING = "agent:warning";
+
+ /** */
+ private static final String EVENT_AGENT_CLOSE = "agent:close";
+
+ /** */
+ private static final int RECONNECT_INTERVAL = 3000;
+
+ /**
+ * Create a trust manager that trusts all certificates It is not using a particular keyStore
+ */
+ private static TrustManager[] getTrustManagers() {
+ return new TrustManager[] {
+ new X509TrustManager() {
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ public void checkClientTrusted(
+ java.security.cert.X509Certificate[] certs, String authType) {
+ }
+
+ public void checkServerTrusted(
+ java.security.cert.X509Certificate[] certs, String authType) {
+ }
+ }};
+ }
+
+ /**
+ * On error listener.
+ */
+ private static final Emitter.Listener onError = new Emitter.Listener() {
+ @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+ @Override public void call(Object... args) {
+ Throwable e = (Throwable)args[0];
+
+ ConnectException ce = X.cause(e, ConnectException.class);
+
+ if (ce != null)
+ log.error("Failed to receive response from server (connection refused).");
+ else {
+ Exception ignore = X.cause(e, SSLHandshakeException.class);
+
+ if (ignore != null) {
+ log.error("Failed to establish SSL connection to server, due to errors with SSL handshake.");
+ log.error("Add to environment variable JVM_OPTS parameter \"-Dtrust.all=true\" to skip certificate validation in case of using self-signed certificate.");
+
+ System.exit(1);
+ }
+
+ ignore = X.cause(e, IOException.class);
+
+ if (ignore != null && "404".equals(ignore.getMessage())) {
+ log.error("Failed to receive response from server (connection refused).");
+
+ return;
+ }
+
+ log.error("Connection error.", e);
+ }
+ }
+ };
+
+ /**
+ * On disconnect listener.
+ */
+ private static final Emitter.Listener onDisconnect = new Emitter.Listener() {
+ @Override public void call(Object... args) {
+ log.error(String.format("Connection closed: %s.", args));
+ }
+ };
+
+ /**
+ * @param args Args.
+ */
+ @SuppressWarnings("BusyWait")
+ public static void main(String[] args) throws Exception {
+ log.info("Starting Apache Ignite Web Console Agent...");
+
+ final AgentConfiguration cfg = new AgentConfiguration();
+
+ JCommander jCommander = new JCommander(cfg);
+
+ String osName = System.getProperty("os.name").toLowerCase();
+
+ jCommander.setProgramName("ignite-web-agent." + (osName.contains("win") ? "bat" : "sh"));
+
+ try {
+ jCommander.parse(args);
+ }
+ catch (ParameterException pe) {
+ log.error("Failed to parse command line parameters: " + Arrays.toString(args), pe);
+
+ jCommander.usage();
+
+ return;
+ }
+
+ String prop = cfg.configPath();
+
+ AgentConfiguration propCfg = new AgentConfiguration();
+
+ try {
+ File f = AgentUtils.resolvePath(prop);
+
+ if (f == null)
+ log.warn("Failed to find agent property file: " + prop);
+ else
+ propCfg.load(f.toURI().toURL());
+ }
+ catch (IOException ignore) {
+ if (!AgentConfiguration.DFLT_CFG_PATH.equals(prop))
+ log.warn("Failed to load agent property file: " + prop, ignore);
+ }
+
+ cfg.merge(propCfg);
+
+ if (cfg.help()) {
+ jCommander.usage();
+
+ return;
+ }
+
+ System.out.println();
+ System.out.println("Agent configuration:");
+ System.out.println(cfg);
+ System.out.println();
+
+ if (cfg.tokens() == null) {
+ String webHost;
+
+ try {
+ webHost = new URI(cfg.serverUri()).getHost();
+ }
+ catch (URISyntaxException e) {
+ log.error("Failed to parse Ignite Web Console uri", e);
+
+ return;
+ }
+
+ System.out.println("Security token is required to establish connection to the web console.");
+ System.out.println(String.format("It is available on the Profile page: https://%s/profile", webHost));
+
+ System.out.print("Enter security tokens separated by comma: ");
+
+ cfg.tokens(Arrays.asList(System.console().readLine().trim().split(",")));
+ }
+
+ final RestHandler restHnd = new RestHandler(cfg);
+
+ try {
+ restHnd.start();
+
+ URI uri = URI.create(cfg.serverUri());
+
+ if (uri.getPort() == -1)
+ uri = URI.create(cfg.serverUri() + ':' + DFLT_SERVER_PORT);
+
+ IO.Options opts = new IO.Options();
+
+ opts.reconnectionDelay = RECONNECT_INTERVAL;
+
+ // Workaround for use self-signed certificate
+ if (Boolean.getBoolean("trust.all")) {
+ SSLContext ctx = SSLContext.getInstance("TLS");
+
+ // Create an SSLContext that uses our TrustManager
+ ctx.init(null, getTrustManagers(), null);
+
+ opts.sslContext = ctx;
+ }
+
+ final Socket client = IO.socket(uri, opts);
+
+ try {
+ Emitter.Listener onConnecting = new Emitter.Listener() {
+ @Override public void call(Object... args) {
+ log.info("Connecting to: " + cfg.serverUri());
+ }
+ };
+
+ Emitter.Listener onConnect = new Emitter.Listener() {
+ @Override public void call(Object... args) {
+ log.info("Connection established.");
+
+ JSONObject authMsg = new JSONObject();
+
+ try {
+ authMsg.put("tokens", cfg.tokens());
+
+ String clsName = AgentLauncher.class.getSimpleName() + ".class";
+
+ String clsPath = AgentLauncher.class.getResource(clsName).toString();
+
+ if (clsPath.startsWith("jar")) {
+ String manifestPath = clsPath.substring(0, clsPath.lastIndexOf('!') + 1) +
+ "/META-INF/MANIFEST.MF";
+
+ Manifest manifest = new Manifest(new URL(manifestPath).openStream());
+
+ Attributes attr = manifest.getMainAttributes();
+
+ authMsg.put("ver", attr.getValue("Implementation-Version"));
+ authMsg.put("bt", attr.getValue("Build-Time"));
+ }
+
+ client.emit("agent:auth", authMsg, new Ack() {
+ @Override public void call(Object... args) {
+ // Authentication failed if response contains args.
+ if (args != null && args.length > 0) {
+ onDisconnect.call(args);
+
+ System.exit(1);
+ }
+
+ log.info("Authentication success.");
+ }
+ });
+ }
+ catch (JSONException | IOException e) {
+ log.error("Failed to construct authentication message", e);
+
+ client.close();
+ }
+ }
+ };
+
+ DatabaseHandler dbHnd = new DatabaseHandler(cfg);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ client
+ .on(EVENT_CONNECTING, onConnecting)
+ .on(EVENT_CONNECT, onConnect)
+ .on(EVENT_CONNECT_ERROR, onError)
+ .on(EVENT_RECONNECTING, onConnecting)
+ .on(EVENT_NODE_REST, restHnd)
+ .on(EVENT_SCHEMA_IMPORT_DRIVERS, dbHnd.availableDriversListener())
+ .on(EVENT_SCHEMA_IMPORT_SCHEMAS, dbHnd.schemasListener())
+ .on(EVENT_SCHEMA_IMPORT_METADATA, dbHnd.metadataListener())
+ .on(EVENT_ERROR, onError)
+ .on(EVENT_DISCONNECT, onDisconnect)
+ .on(EVENT_AGENT_WARNING, new Emitter.Listener() {
+ @Override public void call(Object... args) {
+ log.warn(args[0]);
+ }
+ })
+ .on(EVENT_AGENT_CLOSE, new Emitter.Listener() {
+ @Override public void call(Object... args) {
+ onDisconnect.call(args);
+
+ client.off();
+
+ latch.countDown();
+ }
+ });
+
+ client.connect();
+
+ latch.await();
+ }
+ finally {
+ client.close();
+ }
+ }
+ finally {
+ restHnd.stop();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
new file mode 100644
index 0000000..50a849a
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.ProtectionDomain;
+import org.apache.log4j.Logger;
+
+/**
+ * Utility methods.
+ */
+public class AgentUtils {
+ /** */
+ private static final Logger log = Logger.getLogger(AgentUtils.class.getName());
+
+ /**
+ * Default constructor.
+ */
+ private AgentUtils() {
+ // No-op.
+ }
+
+ /**
+ * @param path Path to normalize.
+ * @return Normalized file path.
+ */
+ public static String normalizePath(String path) {
+ return path != null ? path.replace('\\', '/') : null;
+ }
+
+ /**
+ * @return App folder.
+ */
+ public static File getAgentHome() {
+ try {
+ ProtectionDomain domain = AgentLauncher.class.getProtectionDomain();
+
+ // Should not happen, but to make sure our code is not broken.
+ if (domain == null || domain.getCodeSource() == null || domain.getCodeSource().getLocation() == null) {
+ log.warn("Failed to resolve agent jar location!");
+
+ return null;
+ }
+
+ // Resolve path to class-file.
+ URI classesUri = domain.getCodeSource().getLocation().toURI();
+
+ boolean win = System.getProperty("os.name").toLowerCase().contains("win");
+
+ // Overcome UNC path problem on Windows (http://www.tomergabel.com/JavaMishandlesUNCPathsOnWindows.aspx)
+ if (win && classesUri.getAuthority() != null)
+ classesUri = new URI(classesUri.toString().replace("file://", "file:/"));
+
+ return new File(classesUri).getParentFile();
+ }
+ catch (URISyntaxException | SecurityException ignored) {
+ log.warn("Failed to resolve agent jar location!");
+
+ return null;
+ }
+ }
+
+ /**
+ * Gets file associated with path.
+ * <p>
+ * First check if path is relative to agent home.
+ * If not, check if path is absolute.
+ * If all checks fail, then {@code null} is returned.
+ * <p>
+ *
+ * @param path Path to resolve.
+ * @return Resolved path as file, or {@code null} if path cannot be resolved.
+ */
+ public static File resolvePath(String path) {
+ assert path != null;
+
+ File home = getAgentHome();
+
+ if (home != null) {
+ File file = new File(home, normalizePath(path));
+
+ if (file.exists())
+ return file;
+ }
+
+ // 2. Check given path as absolute.
+ File file = new File(path);
+
+ if (file.exists())
+ return file;
+
+ return null;
+ }
+}
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/AbstractHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
new file mode 100644
index 0000000..7e4e320
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
@@ -0,0 +1,110 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
+import io.socket.client.Ack;
+import io.socket.emitter.Emitter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ * Base class for web socket handlers.
+ */
+abstract class AbstractHandler implements Emitter.Listener {
+ /** JSON object mapper. */
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ static {
+ JsonOrgModule module = new JsonOrgModule();
+
+ mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
+ mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
+
+ mapper.registerModule(module);
+ }
+
+ /**
+ * @param obj Object.
+ * @return {@link JSONObject} or {@link JSONArray}.
+ */
+ private Object toJSON(Object obj) {
+ if (obj instanceof Iterable)
+ return mapper.convertValue(obj, JSONArray.class);
+
+ return mapper.convertValue(obj, JSONObject.class);
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override public final void call(Object... args) {
+ Ack cb = null;
+
+ try {
+ if (args == null || args.length == 0)
+ throw new IllegalArgumentException("Missing arguments.");
+
+ if (args.length > 2)
+ throw new IllegalArgumentException("Wrong arguments count, must be <= 2: " + Arrays.toString(args));
+
+ JSONObject lsnrArgs = null;
+
+ if (args.length == 1) {
+ if (args[0] instanceof JSONObject)
+ lsnrArgs = (JSONObject)args[0];
+ else if (args[0] instanceof Ack)
+ cb = (Ack)args[0];
+ else
+ throw new IllegalArgumentException("Wrong type of argument, must be JSONObject or Ack: " + args[0]);
+ }
+ else {
+ if (args[0] != null && !(args[0] instanceof JSONObject))
+ throw new IllegalArgumentException("Wrong type of argument, must be JSONObject: " + args[0]);
+
+ if (!(args[1] instanceof Ack))
+ throw new IllegalArgumentException("Wrong type of argument, must be Ack: " + args[1]);
+
+ lsnrArgs = (JSONObject)args[0];
+
+ cb = (Ack)args[1];
+ }
+
+ Object res = execute(lsnrArgs == null ? Collections.emptyMap() : mapper.convertValue(lsnrArgs, Map.class));
+
+ if (cb != null)
+ cb.call(null, toJSON(res));
+ }
+ catch (Exception e) {
+ if (cb != null)
+ cb.call(e, null);
+ }
+ }
+
+ /**
+ * Execute command with specified arguments.
+ *
+ * @param args Map with method args.
+ */
+ public abstract Object execute(Map<String, Object> args) throws Exception;
+}
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/DatabaseHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java b/modules/web-console/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-console/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;
+ }
+ }
+}