IGNITE-843 Implemented Web Console.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/eb5ac0ae Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/eb5ac0ae Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/eb5ac0ae Branch: refs/heads/ignite-1.6 Commit: eb5ac0ae5db711f75804842b7a39d3d6f80ffcd4 Parents: a284d05 Author: AKuznetsov <[email protected]> Authored: Tue May 17 23:21:25 2016 +0700 Committer: AKuznetsov <[email protected]> Committed: Tue May 17 23:21:29 2016 +0700 ---------------------------------------------------------------------- .../parser/dialect/DB2MetadataDialect.java | 2 +- modules/web-agent/.gitignore | 2 + modules/web-agent/README.txt | 87 + .../web-agent/assembly/release-web-agent.xml | 74 + modules/web-agent/bin/ignite-web-agent.bat | 70 + modules/web-agent/bin/ignite-web-agent.sh | 87 + modules/web-agent/demo/README.txt | 4 + modules/web-agent/demo/db-init.sql | 102 + modules/web-agent/jdbc-drivers/README.txt | 10 + modules/web-agent/logs/README.txt | 5 + modules/web-agent/pom.xml | 169 + .../console/agent/AgentConfiguration.java | 255 ++ .../ignite/console/agent/AgentLauncher.java | 337 ++ .../apache/ignite/console/agent/AgentUtils.java | 111 + .../console/agent/handlers/AbstractHandler.java | 110 + .../console/agent/handlers/DatabaseHandler.java | 298 ++ .../console/agent/handlers/RestHandler.java | 276 ++ .../ignite/console/demo/AgentClusterDemo.java | 614 ++++ .../ignite/console/demo/AgentMetadataDemo.java | 92 + .../apache/ignite/console/demo/model/Car.java | 152 + .../ignite/console/demo/model/Country.java | 152 + .../ignite/console/demo/model/Department.java | 152 + .../ignite/console/demo/model/Employee.java | 356 ++ .../ignite/console/demo/model/Parking.java | 152 + .../src/main/resources/log4j.properties | 53 + modules/web-console/DEVNOTES.txt | 28 + modules/web-console/README.txt | 36 + modules/web-console/licenses/apache-2.0.txt | 202 ++ modules/web-console/pom.xml | 69 + modules/web-console/src/main/js/.babelrc | 3 + modules/web-console/src/main/js/.eslintrc | 197 ++ modules/web-console/src/main/js/.gitignore | 11 + .../src/main/js/app/data/colors.json | 22 + .../src/main/js/app/data/countries.json | 94 + .../src/main/js/app/data/demo-info.json | 14 + .../src/main/js/app/data/event-types.json | 169 + .../src/main/js/app/data/getting-started.json | 109 + .../src/main/js/app/data/java-classes.json | 18 + .../src/main/js/app/data/java-keywords.json | 55 + .../src/main/js/app/data/java-primitives.json | 9 + .../src/main/js/app/decorator/select.js | 77 + .../src/main/js/app/decorator/tooltip.js | 56 + .../app/directives/bs-affix-update.directive.js | 34 + .../js/app/directives/centered/centered.css | 37 + .../directives/centered/centered.directive.js | 26 + .../hide-on-state-change.directive.js | 31 + .../information/information.directive.js | 30 + .../app/directives/information/information.jade | 20 + .../app/directives/information/information.scss | 56 + .../ui-ace-docker/ui-ace-docker.controller.js | 33 + .../ui-ace-docker/ui-ace-docker.directive.js | 46 + .../directives/ui-ace-docker/ui-ace-docker.jade | 31 + .../ui-ace-java/ui-ace-java.controller.js | 32 + .../ui-ace-java/ui-ace-java.directive.js | 133 + .../app/directives/ui-ace-java/ui-ace-java.jade | 22 + .../ui-ace-pojos/ui-ace-pojos.controller.js | 95 + .../ui-ace-pojos/ui-ace-pojos.directive.js | 46 + .../directives/ui-ace-pojos/ui-ace-pojos.jade | 40 + .../ui-ace-pom/ui-ace-pom.controller.js | 33 + .../ui-ace-pom/ui-ace-pom.directive.js | 41 + .../app/directives/ui-ace-pom/ui-ace-pom.jade | 17 + .../js/app/directives/ui-ace-tabs.directive.js | 23 + .../ui-ace-xml/ui-ace-xml.controller.js | 27 + .../ui-ace-xml/ui-ace-xml.directive.js | 133 + .../app/directives/ui-ace-xml/ui-ace-xml.jade | 17 + .../src/main/js/app/filters/byName.filter.js | 23 + .../src/main/js/app/filters/hasPojo.filter.js | 18 + .../src/main/js/app/helpers/jade/mixins.jade | 587 ++++ modules/web-console/src/main/js/app/index.js | 241 ++ .../src/main/js/app/modules/Demo/Demo.module.js | 165 + .../QueryNotebooks/QueryNotebooks.provider.js | 115 + .../js/app/modules/Version/Version.provider.js | 32 + .../src/main/js/app/modules/ace.module.js | 269 ++ .../js/app/modules/branding/branding.module.js | 46 + .../app/modules/branding/branding.provider.js | 111 + .../app/modules/branding/features.directive.js | 35 + .../js/app/modules/branding/footer.directive.js | 34 + .../modules/branding/header-logo.directive.js | 34 + .../js/app/modules/branding/header-logo.jade | 18 + .../modules/branding/header-title.directive.js | 35 + .../branding/powered-by-apache.directive.js | 35 + .../app/modules/branding/powered-by-apache.jade | 18 + .../js/app/modules/branding/terms.directive.js | 30 + .../configuration/EventGroups.provider.js | 30 + .../modules/configuration/Sidebar.provider.js | 39 + .../configuration/configuration.module.js | 41 + .../configuration/generator/Docker.service.js | 78 + .../configuration/generator/Java.service.js | 21 + .../configuration/generator/Pom.service.js | 214 ++ .../configuration/generator/Xml.service.js | 21 + .../modules/configuration/sidebar.directive.js | 30 + .../modules/dialog/dialog-content.directive.js | 31 + .../modules/dialog/dialog-title.directive.js | 31 + .../js/app/modules/dialog/dialog.controller.js | 40 + .../js/app/modules/dialog/dialog.directive.js | 32 + .../js/app/modules/dialog/dialog.factory.js | 32 + .../src/main/js/app/modules/dialog/dialog.jade | 26 + .../main/js/app/modules/dialog/dialog.module.js | 32 + .../field/bs-select-placeholder.directive.js | 46 + .../js/app/modules/form/field/down.directive.js | 43 + .../modules/form/field/dropdown.directive.js | 84 + .../js/app/modules/form/field/dropdown.jade | 61 + .../main/js/app/modules/form/field/field.css | 23 + .../app/modules/form/field/field.directive.js | 44 + .../main/js/app/modules/form/field/field.jade | 27 + .../field/form-control-feedback.directive.js | 40 + .../form/field/input/autofocus.directive.js | 30 + .../form/field/input/checkbox.directive.js | 67 + .../app/modules/form/field/input/checkbox.jade | 30 + .../form/field/input/datalist.directive.js | 123 + .../app/modules/form/field/input/datalist.jade | 51 + .../form/field/input/number.directive.js | 77 + .../js/app/modules/form/field/input/number.jade | 50 + .../js/app/modules/form/field/input/text.css | 41 + .../modules/form/field/input/text.directive.js | 124 + .../js/app/modules/form/field/input/text.jade | 48 + .../app/modules/form/field/label.directive.js | 47 + .../app/modules/form/field/tooltip.directive.js | 49 + .../js/app/modules/form/field/up.directive.js | 44 + .../src/main/js/app/modules/form/form.module.js | 101 + .../js/app/modules/form/group/add.directive.js | 40 + .../app/modules/form/group/group.directive.js | 81 + .../main/js/app/modules/form/group/group.jade | 21 + .../app/modules/form/group/table.directive.js | 29 + .../main/js/app/modules/form/group/table.jade | 17 + .../app/modules/form/group/tooltip.directive.js | 40 + .../app/modules/form/panel/chevron.directive.js | 53 + .../app/modules/form/panel/panel.directive.js | 37 + .../app/modules/form/panel/revert.directive.js | 53 + .../form/validator/ipaddress.directive.js | 86 + .../validator/java-built-in-class.directive.js | 31 + .../form/validator/java-identifier.directive.js | 31 + .../form/validator/java-keywords.directive.js | 43 + .../validator/java-package-name.directive.js | 31 + .../java-package-specified.directive.js | 34 + .../form/validator/property-unique.directive.js | 47 + .../property-value-specified.directive.js | 31 + .../modules/form/validator/unique.directive.js | 49 + .../getting-started/GettingStarted.provider.js | 112 + .../src/main/js/app/modules/loading/loading.css | 73 + .../js/app/modules/loading/loading.directive.js | 51 + .../main/js/app/modules/loading/loading.jade | 23 + .../js/app/modules/loading/loading.module.js | 26 + .../js/app/modules/loading/loading.service.js | 48 + .../js/app/modules/navbar/Navbar.provider.js | 28 + .../js/app/modules/navbar/Userbar.provider.js | 28 + .../js/app/modules/navbar/navbar.directive.js | 30 + .../main/js/app/modules/navbar/navbar.module.js | 33 + .../js/app/modules/navbar/userbar.directive.js | 48 + .../src/main/js/app/modules/socket.module.js | 41 + .../main/js/app/modules/states/admin.state.js | 34 + .../app/modules/states/configuration.state.js | 202 ++ .../caches/concurrency.directive.js | 27 + .../configuration/caches/concurrency.jade | 65 + .../configuration/caches/general.directive.js | 27 + .../states/configuration/caches/general.jade | 65 + .../configuration/caches/memory.directive.js | 27 + .../states/configuration/caches/memory.jade | 88 + .../configuration/caches/query.directive.js | 27 + .../states/configuration/caches/query.jade | 93 + .../configuration/caches/rebalance.directive.js | 27 + .../states/configuration/caches/rebalance.jade | 65 + .../caches/server-near-cache.directive.js | 27 + .../configuration/caches/server-near-cache.jade | 45 + .../caches/statistics.directive.js | 27 + .../states/configuration/caches/statistics.jade | 37 + .../configuration/caches/store.directive.js | 27 + .../states/configuration/caches/store.jade | 266 ++ .../configuration/clusters/atomic.directive.js | 27 + .../states/configuration/clusters/atomic.jade | 53 + .../configuration/clusters/binary.directive.js | 27 + .../states/configuration/clusters/binary.jade | 100 + .../clusters/communication.directive.js | 27 + .../configuration/clusters/communication.jade | 90 + .../clusters/connector.directive.js | 27 + .../configuration/clusters/connector.jade | 103 + .../clusters/deployment.directive.js | 27 + .../configuration/clusters/deployment.jade | 112 + .../clusters/discovery.directive.js | 27 + .../configuration/clusters/discovery.jade | 81 + .../configuration/clusters/events.directive.js | 27 + .../states/configuration/clusters/events.jade | 37 + .../configuration/clusters/general.directive.js | 27 + .../states/configuration/clusters/general.jade | 70 + .../general/discovery/cloud.directive.js | 27 + .../clusters/general/discovery/cloud.jade | 125 + .../general/discovery/google.directive.js | 27 + .../clusters/general/discovery/google.jade | 35 + .../general/discovery/jdbc.directive.js | 27 + .../clusters/general/discovery/jdbc.jade | 24 + .../general/discovery/multicast.directive.js | 27 + .../clusters/general/discovery/multicast.jade | 109 + .../clusters/general/discovery/s3.directive.js | 27 + .../clusters/general/discovery/s3.jade | 25 + .../general/discovery/shared.directive.js | 27 + .../clusters/general/discovery/shared.jade | 23 + .../clusters/general/discovery/vm.directive.js | 27 + .../clusters/general/discovery/vm.jade | 90 + .../general/discovery/zookeeper.directive.js | 27 + .../clusters/general/discovery/zookeeper.jade | 73 + .../bounded-exponential-backoff.directive.js | 27 + .../bounded-exponential-backoff.jade | 27 + .../zookeeper/retrypolicy/custom.directive.js | 27 + .../discovery/zookeeper/retrypolicy/custom.jade | 22 + .../exponential-backoff.directive.js | 27 + .../retrypolicy/exponential-backoff.jade | 27 + .../zookeeper/retrypolicy/forever.directive.js | 27 + .../zookeeper/retrypolicy/forever.jade | 22 + .../zookeeper/retrypolicy/n-times.directive.js | 27 + .../zookeeper/retrypolicy/n-times.jade | 25 + .../zookeeper/retrypolicy/one-time.directive.js | 27 + .../zookeeper/retrypolicy/one-time.jade | 23 + .../retrypolicy/until-elapsed.directive.js | 27 + .../zookeeper/retrypolicy/until-elapsed.jade | 25 + .../configuration/clusters/igfs.directive.js | 27 + .../states/configuration/clusters/igfs.jade | 37 + .../clusters/marshaller.directive.js | 27 + .../configuration/clusters/marshaller.jade | 69 + .../configuration/clusters/metrics.directive.js | 27 + .../states/configuration/clusters/metrics.jade | 50 + .../configuration/clusters/ssl.directive.js | 27 + .../states/configuration/clusters/ssl.jade | 108 + .../configuration/clusters/swap.directive.js | 27 + .../states/configuration/clusters/swap.jade | 67 + .../configuration/clusters/thread.directive.js | 27 + .../states/configuration/clusters/thread.jade | 48 + .../configuration/clusters/time.directive.js | 27 + .../states/configuration/clusters/time.jade | 47 + .../clusters/transactions.directive.js | 27 + .../configuration/clusters/transactions.jade | 59 + .../configuration/domains/general.directive.js | 27 + .../states/configuration/domains/general.jade | 46 + .../configuration/domains/query.directive.js | 27 + .../states/configuration/domains/query.jade | 169 + .../configuration/domains/store.directive.js | 27 + .../states/configuration/domains/store.jade | 126 + .../states/configuration/igfs/dual.directive.js | 27 + .../modules/states/configuration/igfs/dual.jade | 42 + .../igfs/fragmentizer.directive.js | 27 + .../states/configuration/igfs/fragmentizer.jade | 43 + .../configuration/igfs/general.directive.js | 27 + .../states/configuration/igfs/general.jade | 53 + .../states/configuration/igfs/ipc.directive.js | 27 + .../modules/states/configuration/igfs/ipc.jade | 57 + .../states/configuration/igfs/misc.directive.js | 27 + .../modules/states/configuration/igfs/misc.jade | 108 + .../configuration/igfs/secondary.directive.js | 27 + .../states/configuration/igfs/secondary.jade | 44 + .../configuration/preview-panel.directive.js | 239 ++ .../summary/summary-tabs.directive.js | 50 + .../configuration/summary/summary.controller.js | 360 ++ .../configuration/summary/summary.resource.js | 40 + .../main/js/app/modules/states/logout.state.js | 36 + .../js/app/modules/states/password.state.js | 46 + .../main/js/app/modules/states/profile.state.js | 34 + .../main/js/app/modules/states/signin.state.js | 52 + .../src/main/js/app/modules/states/sql.state.js | 46 + .../main/js/app/modules/user/Auth.service.js | 73 + .../main/js/app/modules/user/User.service.js | 65 + .../src/main/js/app/modules/user/user.module.js | 28 + .../js/app/services/AgentMonitor.service.js | 337 ++ .../main/js/app/services/ChartColors.service.js | 22 + .../main/js/app/services/Countries.service.js | 31 + .../main/js/app/services/InetAddress.service.js | 53 + .../main/js/app/services/JavaTypes.service.js | 84 + .../src/main/js/app/services/cleanup.service.js | 44 + .../src/main/js/app/services/confirm.service.js | 70 + .../src/main/js/build/system.config.js | 415 +++ .../src/main/js/controllers/admin-controller.js | 92 + .../main/js/controllers/caches-controller.js | 493 +++ .../main/js/controllers/clusters-controller.js | 555 +++ .../src/main/js/controllers/common-module.js | 1759 ++++++++++ .../main/js/controllers/domains-controller.js | 1786 ++++++++++ .../src/main/js/controllers/igfs-controller.js | 441 +++ .../main/js/controllers/profile-controller.js | 84 + .../src/main/js/controllers/sql-controller.js | 1568 +++++++++ .../src/main/js/generator/generator-common.js | 570 ++++ .../src/main/js/generator/generator-java.js | 3179 ++++++++++++++++++ .../src/main/js/generator/generator-optional.js | 25 + .../main/js/generator/generator-properties.js | 149 + .../src/main/js/generator/generator-readme.js | 85 + .../src/main/js/generator/generator-xml.js | 1769 ++++++++++ .../src/main/js/gulpfile.babel.js/index.js | 26 + .../src/main/js/gulpfile.babel.js/paths.js | 101 + .../main/js/gulpfile.babel.js/tasks/build.js | 21 + .../main/js/gulpfile.babel.js/tasks/bundle.js | 76 + .../main/js/gulpfile.babel.js/tasks/clean.js | 35 + .../main/js/gulpfile.babel.js/tasks/connect.js | 47 + .../src/main/js/gulpfile.babel.js/tasks/copy.js | 57 + .../main/js/gulpfile.babel.js/tasks/eslint.js | 43 + .../gulpfile.babel.js/tasks/ignite-modules.js | 56 + .../src/main/js/gulpfile.babel.js/tasks/jade.js | 40 + .../src/main/js/gulpfile.babel.js/tasks/sass.js | 25 + .../main/js/gulpfile.babel.js/tasks/watch.js | 39 + .../src/main/js/ignite_modules/README.txt | 6 + .../src/main/js/ignite_modules/index.js | 27 + modules/web-console/src/main/js/package.json | 271 ++ .../web-console/src/main/js/public/favicon.ico | Bin 0 -> 1150 bytes .../src/main/js/public/images/cache.png | Bin 0 -> 23700 bytes .../src/main/js/public/images/cluster.png | Bin 0 -> 29670 bytes .../src/main/js/public/images/docker.png | Bin 0 -> 521 bytes .../src/main/js/public/images/domains.png | Bin 0 -> 23828 bytes .../src/main/js/public/images/igfs.png | Bin 0 -> 14307 bytes .../src/main/js/public/images/ignite-logo.png | Bin 0 -> 1982 bytes .../main/js/public/images/[email protected] | Bin 0 -> 3325 bytes .../src/main/js/public/images/ignite-puzzle.png | Bin 0 -> 71974 bytes .../src/main/js/public/images/java.png | Bin 0 -> 170 bytes .../src/main/js/public/images/pb-ignite.png | Bin 0 -> 3493 bytes .../src/main/js/public/images/[email protected] | Bin 0 -> 8558 bytes .../src/main/js/public/images/query-chart.png | Bin 0 -> 16637 bytes .../main/js/public/images/query-metadata.png | Bin 0 -> 32298 bytes .../src/main/js/public/images/query-table.png | Bin 0 -> 42253 bytes .../src/main/js/public/images/summary.png | Bin 0 -> 31997 bytes .../src/main/js/public/images/xml.png | Bin 0 -> 232 bytes .../public/stylesheets/_bootstrap-custom.scss | 65 + .../stylesheets/_bootstrap-variables.scss | 891 +++++ .../stylesheets/_font-awesome-custom.scss | 31 + .../src/main/js/public/stylesheets/style.scss | 2128 ++++++++++++ .../main/js/public/stylesheets/variables.scss | 28 + modules/web-console/src/main/js/serve.js | 116 + modules/web-console/src/main/js/serve/agent.js | 601 ++++ .../src/main/js/serve/agent_dists/README.txt | 7 + modules/web-console/src/main/js/serve/app.js | 42 + .../web-console/src/main/js/serve/browser.js | 304 ++ .../main/js/serve/config/settings.json.sample | 26 + .../web-console/src/main/js/serve/configure.js | 83 + .../web-console/src/main/js/serve/keys/test.crt | 13 + .../web-console/src/main/js/serve/keys/test.key | 18 + modules/web-console/src/main/js/serve/mail.js | 75 + modules/web-console/src/main/js/serve/mongo.js | 620 ++++ .../src/main/js/serve/routes/admin.js | 126 + .../src/main/js/serve/routes/agent.js | 82 + .../src/main/js/serve/routes/caches.js | 132 + .../src/main/js/serve/routes/clusters.js | 146 + .../src/main/js/serve/routes/demo.js | 135 + .../src/main/js/serve/routes/demo/caches.json | 87 + .../src/main/js/serve/routes/demo/clusters.json | 50 + .../src/main/js/serve/routes/demo/domains.json | 307 ++ .../src/main/js/serve/routes/demo/igfss.json | 10 + .../src/main/js/serve/routes/domains.js | 195 ++ .../src/main/js/serve/routes/igfs.js | 122 + .../src/main/js/serve/routes/notebooks.js | 121 + .../src/main/js/serve/routes/profile.js | 95 + .../src/main/js/serve/routes/public.js | 228 ++ .../src/main/js/serve/routes/routes.js | 103 + .../web-console/src/main/js/serve/settings.js | 84 + modules/web-console/src/main/js/views/base.jade | 22 + .../src/main/js/views/configuration/caches.jade | 52 + .../main/js/views/configuration/clusters.jade | 60 + .../js/views/configuration/domains-import.jade | 196 ++ .../main/js/views/configuration/domains.jade | 66 + .../src/main/js/views/configuration/igfs.jade | 51 + .../main/js/views/configuration/sidebar.jade | 29 + .../summary-project-structure.jade | 27 + .../js/views/configuration/summary-tabs.jade | 25 + .../main/js/views/configuration/summary.jade | 152 + .../src/main/js/views/includes/footer.jade | 23 + .../src/main/js/views/includes/header.jade | 48 + .../web-console/src/main/js/views/index.jade | 66 + .../web-console/src/main/js/views/reset.jade | 48 + .../src/main/js/views/settings/admin.jade | 76 + .../src/main/js/views/settings/profile.jade | 76 + .../web-console/src/main/js/views/signin.jade | 159 + .../src/main/js/views/sql/cache-metadata.jade | 40 + .../src/main/js/views/sql/chart-settings.jade | 40 + .../src/main/js/views/sql/notebook-new.jade | 31 + .../src/main/js/views/sql/paragraph-rate.jade | 31 + .../web-console/src/main/js/views/sql/sql.jade | 180 + .../main/js/views/templates/agent-download.jade | 48 + .../src/main/js/views/templates/alert.jade | 21 + .../main/js/views/templates/batch-confirm.jade | 32 + .../src/main/js/views/templates/clone.jade | 31 + .../src/main/js/views/templates/confirm.jade | 31 + .../src/main/js/views/templates/demo-info.jade | 45 + .../src/main/js/views/templates/dropdown.jade | 21 + .../js/views/templates/getting-started.jade | 32 + .../src/main/js/views/templates/message.jade | 26 + .../src/main/js/views/templates/pagination.jade | 32 + .../src/main/js/views/templates/select.jade | 26 + .../js/views/templates/validation-error.jade | 25 + modules/web-console/src/test/js/routes/agent.js | 94 + parent/pom.xml | 12 + pom.xml | 9 + 383 files changed, 40336 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/schema-import-db/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java ---------------------------------------------------------------------- diff --git a/modules/schema-import-db/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java b/modules/schema-import-db/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java index b191ec3..d277e4b 100644 --- a/modules/schema-import-db/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java +++ b/modules/schema-import-db/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java @@ -30,4 +30,4 @@ public class DB2MetadataDialect extends JdbcMetadataDialect { return new HashSet<>(Arrays.asList("SYSIBM", "SYSCAT", "SYSSTAT", "SYSTOOLS", "SYSFUN", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS", "SYSPROC", "SYSPUBLIC")); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-agent/.gitignore ---------------------------------------------------------------------- diff --git a/modules/web-agent/.gitignore b/modules/web-agent/.gitignore new file mode 100644 index 0000000..57dd45e --- /dev/null +++ b/modules/web-agent/.gitignore @@ -0,0 +1,2 @@ +logs/*.log.* +jdbc-drivers/*.jar http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-agent/README.txt ---------------------------------------------------------------------- diff --git a/modules/web-agent/README.txt b/modules/web-agent/README.txt new file mode 100644 index 0000000..0d8d4ac --- /dev/null +++ b/modules/web-agent/README.txt @@ -0,0 +1,87 @@ +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: + token + server-uri + node-uri + driver-folder + + Example configuration file: + token=1a2b3c4d5f + serverURI=http://console.example.com:3001 + +Security token: + 1) By default token will be included into downloaded agent zip. + 2) You can get/change token in your profile. + +Ignite Web agent requirements: + 1) Ignite node should be started with REST server (move ignite-rest-http folder from lib/optional/ to lib/). + 2) Pass Ignite node REST server URI to agent. + +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, --token + User's security token + +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 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/eb5ac0ae/modules/web-agent/assembly/release-web-agent.xml ---------------------------------------------------------------------- diff --git a/modules/web-agent/assembly/release-web-agent.xml b/modules/web-agent/assembly/release-web-agent.xml new file mode 100644 index 0000000..eb7da95 --- /dev/null +++ b/modules/web-agent/assembly/release-web-agent.xml @@ -0,0 +1,74 @@ +<?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>README*</include> + <include>LICENSE*</include> + <include>NOTICE*</include> + </includes> + </fileSet> + <fileSet> + <directory>${basedir}/bin</directory> + <outputDirectory>/</outputDirectory> + <filtered>true</filtered> + <includes> + <include>**/*.bat</include> + </includes> + </fileSet> + <fileSet> + <directory>${basedir}/bin</directory> + <outputDirectory>/</outputDirectory> + <filtered>true</filtered> + <fileMode>0755</fileMode> + <includes> + <include>**/*.sh</include> + </includes> + </fileSet> + <fileSet> + <directory>${basedir}/logs</directory> + <outputDirectory>/logs</outputDirectory> + <includes> + <include>README*</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/eb5ac0ae/modules/web-agent/bin/ignite-web-agent.bat ---------------------------------------------------------------------- diff --git a/modules/web-agent/bin/ignite-web-agent.bat b/modules/web-agent/bin/ignite-web-agent.bat new file mode 100644 index 0000000..5b3f24c --- /dev/null +++ b/modules/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 ignite-web-agent-${version}.jar 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/eb5ac0ae/modules/web-agent/bin/ignite-web-agent.sh ---------------------------------------------------------------------- diff --git a/modules/web-agent/bin/ignite-web-agent.sh b/modules/web-agent/bin/ignite-web-agent.sh new file mode 100644 index 0000000..6d0a1b5 --- /dev/null +++ b/modules/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 ignite-web-agent-${version}.jar org.apache.ignite.console.agent.AgentLauncher "$@" http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-agent/demo/README.txt ---------------------------------------------------------------------- diff --git a/modules/web-agent/demo/README.txt b/modules/web-agent/demo/README.txt new file mode 100644 index 0000000..17e5074 --- /dev/null +++ b/modules/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/eb5ac0ae/modules/web-agent/demo/db-init.sql ---------------------------------------------------------------------- diff --git a/modules/web-agent/demo/db-init.sql b/modules/web-agent/demo/db-init.sql new file mode 100644 index 0000000..0688ea0 --- /dev/null +++ b/modules/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/eb5ac0ae/modules/web-agent/jdbc-drivers/README.txt ---------------------------------------------------------------------- diff --git a/modules/web-agent/jdbc-drivers/README.txt b/modules/web-agent/jdbc-drivers/README.txt new file mode 100644 index 0000000..cad43b7 --- /dev/null +++ b/modules/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/eb5ac0ae/modules/web-agent/logs/README.txt ---------------------------------------------------------------------- diff --git a/modules/web-agent/logs/README.txt b/modules/web-agent/logs/README.txt new file mode 100644 index 0000000..3a220eb --- /dev/null +++ b/modules/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/eb5ac0ae/modules/web-agent/pom.xml ---------------------------------------------------------------------- diff --git a/modules/web-agent/pom.xml b/modules/web-agent/pom.xml new file mode 100644 index 0000000..afca554 --- /dev/null +++ b/modules/web-agent/pom.xml @@ -0,0 +1,169 @@ +<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" 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> + <version>1.6.0-SNAPSHOT</version> + + <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>2.7.1</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-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> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java new file mode 100644 index 0000000..ffd30a5 --- /dev/null +++ b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java @@ -0,0 +1,255 @@ +/* + * 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.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", "--token"}, description = "User's security token used to establish connection to Ignite Console.") + private String tok; + + /** */ + @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 Token. + */ + public String token() { + return tok; + } + + /** + * @param tok Token. + */ + public void token(String tok) { + this.tok = tok; + } + + /** + * @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("token"); + + if (val != null) + token(val); + + 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 (tok == null) + token(cmd.token()); + + 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 (tok != null && tok.length() > 0) { + sb.append("User's security token : "); + + 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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java new file mode 100644 index 0000000..4b99a92 --- /dev/null +++ b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java @@ -0,0 +1,337 @@ +/* + * 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.SocketException; +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_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[0])); + } + }; + + /** + * @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.token() == 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 token: "); + + cfg.token(System.console().readLine().trim()); + } + + 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("token", cfg.token()); + + 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("Authentication failed: " + args[0]); + + 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_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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java new file mode 100644 index 0000000..50a849a --- /dev/null +++ b/modules/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/eb5ac0ae/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java ---------------------------------------------------------------------- diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java b/modules/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-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; +}
