├── .gitignore
├── README.md
├── demo
├── commands
│ └── mycommand.groovy
├── server
│ ├── README.md
│ └── server.js
└── standalone
│ ├── README.md
│ └── conf.json
├── pom.xml
└── src
├── main
├── assemblies
│ └── mod.xml
├── java
│ └── org
│ │ └── vertx
│ │ └── mods
│ │ ├── CRaSHBusMod.java
│ │ ├── Format.java
│ │ ├── VertxCommand.java
│ │ ├── VertxPluginLifeCycle.java
│ │ └── VertxProcessContext.java
└── resources
│ ├── crash
│ └── commands
│ │ └── vertx
│ │ ├── bus.groovy
│ │ ├── module.groovy
│ │ ├── sharedmap.groovy
│ │ ├── verticle.groovy
│ │ └── vertx.groovy
│ └── mod.json
└── test
├── java
└── org
│ └── vertx
│ ├── java
│ └── busmods
│ │ └── CRaSHBusMod.java
│ └── mods
│ └── VertxTestCase.java
├── mods
└── org.crashub.shell-v1.0
│ └── mod.json
└── resources
└── log4j.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | target
3 | *.versionsBackup
4 | *.releaseBackup
5 | release.properties
6 | .idea
7 | *.iml
8 | derby.log
9 | nul
10 | .classpath
11 | .project
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | The module mod-shell provides an embedded shell for Vert.x based on [CRaSH shell](https://github.com/crashub/crash).
2 |
3 | # Features
4 |
5 | * Extend Vertx with a command line interface
6 | * Script Vert.x
7 | * Write your own commands in Groovy or Java (more languages later...)
8 | * Execute commands from the event bus
9 | * Advanced Vert.x management
10 | * List Vert.x http and net servers
11 | * List Vert.x deployments
12 | * Interact with Vert.x shared maps
13 | * Hot deploy a module or a verticle
14 | * Hot undeploy a Vert.x deployment
15 | * Interact with the event bus: send or receive messages
16 | * Advanced shell features
17 | * Powerfull REPL
18 | * JVM commands : jdbc, thread, log, ...
19 | * Various plugin : mail, cron, ...
20 | * Writing custom commands is easy
21 | * Advance completion
22 | * SSH access
23 |
24 | # Documentation
25 |
26 | * This page
27 | * Vertx.shell [screencast](https://vimeo.com/67557338)
28 | * Official CRaSH [documentation](http://www.crashub.org/beta/reference.html)
29 |
30 | # Examples
31 |
32 | * [Server demo](https://github.com/crashub/mod-shell/tree/master/demo/server) : deploy vertx.shell as a module
33 | * [Standalone demo](https://github.com/crashub/mod-shell/tree/master/demo/standalone) : run vert.x shell as a module
34 |
35 | # Status
36 |
37 | * 2.0.7 stable for Vert.x 2.0.2-final
38 | * 2.1.0 stable for Vert.x 2.1.0
39 | * Published in Maven Central
40 |
41 | # Usage
42 |
43 | ## In your application
44 |
45 | Deploy the module org.crashub~vertx.shell in your verticle.
46 |
47 | ## Standalone
48 |
49 | echo '{"crash.auth": "simple","crash.auth.simple.username": "admin","crash.auth.simple.password": "admin","crash.ssh.port":2000}' > conf.json
50 | vertx runmod org.crashub~vertx.shell~2.1.0 -conf conf.json
51 |
52 | ## As a Vert.x module
53 |
54 | Deploy the org.crashub~vertx.shell~2.1.0 module from your verticle.
55 |
56 | # Configuration
57 |
58 | Default config:
59 |
60 | {
61 | "crash.auth": "simple",
62 | "crash.auth.simple.username": "admin",
63 | "crash.auth.simple.password": "admin",
64 | "crash.ssh.port": "2000"
65 | }
66 |
67 |
68 | Configuration is mostly based on CRaSH configuration explained in CRaSH [documentation](http://www.crashub.org/beta/reference.html):
69 |
70 | # Walkthrough
71 |
72 | ## Install
73 |
74 | Install the shell module:
75 |
76 | vertx install org.crashub~vertx.shell~2.1.0
77 | echo '{"crash.auth": "simple","crash.auth.simple.username": "admin","crash.auth.simple.password": "admin"}' > conf.json
78 | vertx runmod org.crashub~vertx.shell~2.1.0 -conf conf.json
79 |
80 | ## Receive and send messages
81 |
82 | Create a message subscriber
83 |
84 | (! 576)-> ssh -p 2000 admin@localhost
85 | admin@localhost's password:
86 | Welcome to Juliens-MacBook-Pro.local + !
87 | It is Sat Jan 12 15:47:50 CET 2013 now
88 | % bus subscribe the_address
89 |
90 | Log in with another console and send a message on the_address:
91 |
92 | (! 501)-> ssh -p 2000 admin@localhost
93 | admin@localhost's password:
94 | Welcome to Juliens-MacBook-Pro.local + !
95 | It is Sat Jan 12 15:48:52 CET 2013 now
96 | % bus send the_address Hello
97 |
98 |
99 | ## Send an email with the Mailer module
100 |
101 | Create the file server.js:
102 |
103 | var container = require('vertx/container');
104 | container.deployModule("io.vertx~mod-mailer~2.0.3-beta2", {
105 | "address": "test.my_mailer",
106 | "host": "smtp.googlemail.com",
107 | "port": 465,
108 | "ssl": true,
109 | "auth": true,
110 | "username": "username",
111 | "password": "password"
112 | });
113 | container.deployModule("org.crashub~vertx.shell~2.1.0", {
114 | "cmd": ".",
115 | "crash.auth": "simple",
116 | "crash.auth.simple.username": "admin",
117 | "crash.auth.simple.password": "admin",
118 | "crash.ssh.port": 2000
119 | });
120 |
121 | Run Vert.x:
122 |
123 | vertx run server.js
124 |
125 | Use the shell:
126 |
127 | (! 569)-> ssh -p 2000 admin@localhost
128 | admin@localhost's password:
129 | Welcome to Juliens-MacBook-Pro.local + !
130 | It is Sat Jan 12 15:28:37 CET 2013 now
131 | % bus send -f JSON test.my_mailer {"from":"julien.viet@gmail.com","to":"julien@julienviet.com","subject":"test","body":"sent from Vert.x"}
132 |
133 | ## Interact with the JDBC module
134 |
135 | Create the server.js file:
136 |
137 | var container = require('vertx/container');
138 | container.deployModule("com.bloidonia~mod-jdbc-persistor~2.0.3-beta5", {
139 | "address" : "db",
140 | "driver" : "org.hsqldb.jdbcDriver",
141 | "url" : "jdbc:hsqldb:mem:test",
142 | "username" : "",
143 | "password" : ""
144 | });
145 | container.deployModule("org.crashub~vertx.shell~2.1.0", {
146 | "cmd": ".",
147 | "crash.auth": "simple",
148 | "crash.auth.simple.username": "admin",
149 | "crash.auth.simple.password": "admin",
150 | "crash.ssh.port": 2000
151 | });
152 |
153 | Copy the HSLQDB jar in your $VERTX_HOME/lib.
154 |
155 | Run Vert.x:
156 |
157 | vertx run server.js
158 |
159 | Use the JDBC module:
160 |
161 | (! 575)-> ssh -p 2000 admin@localhost
162 | admin@localhost's password:
163 | It is Sat Jan 12 15:44:58 CET 2013 now
164 | % bus send -f JSON -r db { "action": "select", "stmt": "SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS" }
165 | {"result":[{"INITIAL_SCHEMA":null,"ADMIN":true,"USER_NAME":""}],"status":"ok"}
166 |
167 | The -r option stands for reply and tell the command to wait and block until a reply is provided after sending the message.
168 | This is useful with the jdbc module as it sends the result of statement in a response.
169 |
170 | ## Request executor
171 |
172 | CRaSH registers an event handler to the "crash.execute" address which process shell requests. This feature is experimental
173 | at the moment (feedback welcome).
174 |
175 | The format of the event message is Json and contains the mandatory _requests_ String array field.
176 |
177 | % bus publish --format JSON crash.execute {"requests":["help"]}
178 |
179 | The optional _replyTo_ field can be used, when specified the handler sends response events to the _replyTo_ address:
180 |
181 | % bus publish --format JSON crash.execute {"requests":["help"],"replyTo":"screen"}
182 |
183 | The _vertx execute_ command can be used to make this easier, it will _publish_ the message:
184 |
185 | % vertx execute help
186 |
187 | Special care should be ported to the request arguments whitespaces:
188 |
189 | % vertx execute "thread ls"
190 |
191 | Several requests can be specified, when a requests ends, the response is sent and the next request is processed. Therefore
192 | the execution order is sequential.
193 |
194 | % vertx execute "repl groovy" "1+1"
195 |
196 | The _bus subscribe_ command can be used to receive the responses, of course this should be done in another
197 | terminal:
198 |
199 | % bus subscribe screen
200 |
201 | ## Creating custom commands in Groovy or Java
202 |
203 | Pretty much like the first example, however we add the current directory under the "cmd" key in the configuration:
204 |
205 | echo '{"cmd":".","crash.auth": "simple","crash.auth.simple.username": "admin","crash.auth.simple.password": "admin"}' > conf.json
206 |
207 | Edit hello.groovy
208 |
209 | return "Hello from ${context.attributes.vertx}"
210 |
211 | Run Vert.x:
212 |
213 | vertx runmod org.crashub~vertx.shell~2.1.0 -conf conf.json
214 |
215 | Use the hello command:
216 |
217 | (! 505)-> ssh -p 2000 admin@localhost
218 | admin@localhost's password:
219 | Welcome to Juliens-MacBook-Pro.local + !
220 | It is Sat Jan 12 16:41:50 CET 2013 now
221 | % hello
222 | Hello from org.vertx.java.core.impl.DefaultVertx@5e6b6477
223 |
224 | Inside a Groovy command the current Vertx and Container objects are available under
225 |
226 | def vertx = context.attributes.vertx
227 | def container = context.attributes.container
228 |
229 | For more information about CRaSH commands please read the [documentation](http://www.crashub.org/beta/reference.html)
230 |
231 | Commands located in _cmd_ are live reloaded. Note that commands located under _crash/commands_ are loaded only once as they are
232 | considered as classpath commands (and classpath is not supposed to change).
233 |
234 | # Vert.x commands
235 |
236 | The module embeds an SSH server to an embedded shell in Vert.x . CRaSH comes out of the box with a useful bunch of commands,
237 | however the Vert.x integration provides commands for Vert.x. You can look or modify the existing commands in the mods directory
238 | ($VERTX_MODS) as resources under $VERTX_MODS/org.crashub~vertx.shell~2.1.0/crash/commands/vertx :
239 |
240 | (! 561)-> ls -l $VERTX_MODS/org.crashub~vertx.shell~2.1.0/crash/commands/vertx
241 | total 40
242 | -rw-r--r-- 1 julien staff 3463 Jan 12 16:17 bus.groovy
243 | -rw-r--r-- 1 julien staff 1213 Jan 12 16:17 module.groovy
244 | -rw-r--r-- 1 julien staff 2212 Jan 12 16:17 sharedmap.groovy
245 | -rw-r--r-- 1 julien staff 2016 Jan 12 16:17 verticle.groovy
246 | -rw-r--r-- 1 julien staff 3150 Jan 12 16:17 vertx.groovy
247 |
248 | You can modify the existing commands if you like or add new commands, such commands will be visible each time the module
249 | is deployed.
250 |
251 | ## help command
252 |
253 | (! 566)-> ssh -p 2000 admin@localhost
254 | admin@localhost's password:
255 | It is Sat Jan 12 15:09:46 CET 2013 now
256 | % help
257 | Try one of these commands with the -h or --help switch:
258 |
259 | NAME DESCRIPTION
260 | bus interact with the vert.x event bus
261 | module interact with vert.x modules
262 | sharedmap interact with the vert.x shared map
263 | verticle interact with vert.x verticles
264 | vertx interact with vert.x
265 |
266 | ## vertx command
267 |
268 | usage: vertx [-h | --help] COMMAND [ARGS]
269 |
270 | The most commonly used vertx commands are:
271 | execute execute a shell request
272 | net list existing net servers
273 | config display vert.x config
274 | undeploy undeploy a deployment
275 | deployments list existing deployments
276 | deployment Provide more info about an existing deployment
277 | http list existing http servers
278 |
279 |
280 | ## module command
281 |
282 | usage: module [-h | --help] COMMAND [ARGS]
283 |
284 | The most commonly used module commands are:
285 | deploy deploy a module
286 |
287 | ## sharedmap command
288 |
289 | usage: sharedmap [-h | --help] COMMAND [ARGS]
290 |
291 | The most commonly used sharedmap commands are:
292 | get get a value
293 | put put a value
294 | clear clear a map
295 | destroy destroy a shared map
296 | keys list content of a map
297 | rm remove a value
298 |
299 | ## verticle command
300 |
301 | usage: verticle [-h | --help] COMMAND [ARGS]
302 |
303 | The most commonly used verticle commands are:
304 | deploy deploy a verticle
305 |
306 | ## bus command
307 |
308 | usage: bus [-h | --help] COMMAND [ARGS]
309 |
310 | The most commonly used bus commands are:
311 | publish publish a JSON object as a message
312 | send send a message on the bus
313 | subscribe read message from the bus
314 |
--------------------------------------------------------------------------------
/demo/commands/mycommand.groovy:
--------------------------------------------------------------------------------
1 | return "HELLO WORLD"
--------------------------------------------------------------------------------
/demo/server/README.md:
--------------------------------------------------------------------------------
1 | Run with
2 |
3 | vertx run server.js
4 |
5 | Login (pass=admin) with
6 |
7 | ssh -p 2000 admin@localhost
8 |
--------------------------------------------------------------------------------
/demo/server/server.js:
--------------------------------------------------------------------------------
1 | // A small server setup with mod-shell
2 |
3 | var vertx = require('vertx');
4 | var console = require('vertx/console');
5 | var container = require('vertx/container');
6 |
7 | // Shared map
8 | var map = vertx.getMap('demo.mymap');
9 | map.put('some-key', 'some-value');
10 |
11 | // Deploy mod-shell and additional modules
12 | container.deployModule("com.bloidonia~mod-jdbc-persistor~2.0.0-beta5", {
13 | "address" : "db",
14 | "driver" : "org.hsqldb.jdbcDriver",
15 | "url" : "jdbc:hsqldb:mem:test",
16 | "username" : "",
17 | "password" : ""
18 | });
19 | container.deployModule("io.vertx~mod-mailer~2.0.0-beta2", {
20 | "address": "test.my_mailer",
21 | "host": "smtp.googlemail.com",
22 | "port": 465,
23 | "ssl": true,
24 | "auth": true,
25 | "username": "username",
26 | "password": "password"
27 | });
28 | container.deployModule("org.crashub~vertx.shell~2.1.0", {
29 | "cmd": "../commands",
30 | "crash.auth": "simple",
31 | "crash.auth.simple.username": "admin",
32 | "crash.auth.simple.password": "admin",
33 | "crash.ssh.port": 2000
34 | });
35 |
36 |
--------------------------------------------------------------------------------
/demo/standalone/README.md:
--------------------------------------------------------------------------------
1 | Run with
2 |
3 | vertx runmod org.crashub~vertx.shell~2.1.0 -conf conf.json
4 |
5 | Login (pass=admin) with
6 |
7 | ssh -p 2000 admin@localhost
8 |
--------------------------------------------------------------------------------
/demo/standalone/conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "../commands",
3 | "crash.auth": "simple",
4 | "crash.auth.simple.username": "admin",
5 | "crash.auth.simple.password": "admin",
6 | "crash.ssh.port":2000}
7 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | org.crashub
4 | vertx.shell
5 | jar
6 | 2.1.1-SNAPSHOT
7 |
8 | org.sonatype.oss
9 | oss-parent
10 | 7
11 |
12 | Shell module for Vert.x
13 | A Vert.x module providing remote shell access based on CRaSH shell
14 | http://maven.apache.org
15 |
16 | Crashub
17 | http://www.crashub.org
18 |
19 |
20 |
21 | LGPL, version 2.1
22 | http://www.opensource.org/licenses/lgpl-license.php
23 |
24 |
25 |
26 | scm:git:git://github.com/crashub/mod-shell.git
27 | scm:git:ssh://git@github.com/crashub/mod-shell.git
28 | http://www.crashub.org
29 |
30 |
31 |
32 | julien.viet
33 | Julien Viet
34 | julien.viet@exoplatform.com
35 |
36 | Owner
37 |
38 |
39 |
40 |
41 |
42 |
43 | false
44 | -Psign-artifacts
45 | false
46 | true
47 |
48 |
49 | 7
50 | 7
51 |
52 |
53 | UTF-8
54 |
55 |
56 | true
57 |
58 | 1.3.0
59 | 2.1
60 |
61 |
62 |
63 |
64 |
65 | io.vertx
66 | vertx-core
67 | ${vertx.version}
68 |
69 |
70 | io.vertx
71 | vertx-platform
72 | ${vertx.version}
73 |
74 |
75 |
76 | org.crashub
77 | crash.cli
78 | ${crash.version}
79 |
80 |
81 | org.crashub
82 | crash.shell
83 | ${crash.version}
84 |
85 |
86 | org.codehaus.groovy
87 | groovy-all
88 | 1.8.9
89 |
90 |
91 | junit
92 | junit
93 |
94 |
95 |
96 |
97 |
98 |
99 | org.crashub
100 | crash.connectors.ssh
101 | ${crash.version}
102 |
103 |
104 | org.apache.mina
105 | mina-core
106 | 2.0.7
107 |
108 |
109 | org.apache.sshd
110 | sshd-core
111 | 0.11.0
112 |
113 |
114 | org.apache.sshd
115 | sshd-pam
116 | 0.11.0
117 |
118 |
119 | org.bouncycastle
120 | bcprov-jdk15on
121 | 1.49
122 |
123 |
124 | org.bouncycastle
125 | bcpkix-jdk15on
126 | 1.49
127 |
128 |
129 | org.slf4j
130 | slf4j-api
131 | 1.7.2
132 |
133 |
134 | org.slf4j
135 | slf4j-jdk14
136 | 1.7.2
137 |
138 |
139 |
140 | junit
141 | junit
142 | 4.10
143 | test
144 |
145 |
146 | io.vertx
147 | testtools
148 | 2.0.0-final
149 | test
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | org.apache.maven.plugins
158 | maven-source-plugin
159 | 2.1.2
160 |
161 |
162 | org.apache.maven.plugins
163 | maven-release-plugin
164 | 2.1
165 |
166 |
167 | org.apache.maven.plugins
168 | maven-javadoc-plugin
169 | 2.8
170 |
171 |
172 | org.apache.maven.plugins
173 | maven-compiler-plugin
174 | 2.3.2
175 |
176 |
177 | org.apache.maven.plugins
178 | maven-jar-plugin
179 | 2.3.1
180 |
181 |
182 | org.apache.maven.plugins
183 | maven-install-plugin
184 | 2.3.1
185 |
186 |
187 | org.apache.maven.plugins
188 | maven-deploy-plugin
189 | 2.5
190 |
191 |
192 | org.apache.maven.plugins
193 | maven-clean-plugin
194 | 2.4.1
195 |
196 |
197 | org.apache.maven.plugins
198 | maven-surefire-plugin
199 | 2.12
200 |
201 |
202 | src/test/mods
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | maven-assembly-plugin
213 | 2.3
214 |
215 | true
216 |
217 |
218 |
219 | mod
220 |
221 | single
222 |
223 | package
224 |
225 | src/main/assemblies/mod.xml
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 | org.apache.maven.plugins
234 | maven-source-plugin
235 |
236 |
237 | attach-sources
238 |
239 | jar
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 | org.apache.maven.plugins
248 | maven-release-plugin
249 |
250 | forked-path
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 | sign-artifacts
260 |
261 |
262 |
263 |
264 | org.apache.maven.plugins
265 | maven-gpg-plugin
266 |
267 |
268 |
269 | sign
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
--------------------------------------------------------------------------------
/src/main/assemblies/mod.xml:
--------------------------------------------------------------------------------
1 |
4 | mod
5 |
6 | zip
7 |
8 |
9 | true
10 | /
11 |
12 |
13 |
14 | ${project.build.outputDirectory}
15 | /
16 |
17 |
18 |
19 |
20 |
21 |
22 | org.crashub:crash.cli
23 | org.crashub:crash.shell
24 | org.crashub:crash.connectors.ssh
25 | org.apache.mina:mina-core
26 | org.apache.sshd:sshd-core
27 | org.apache.sshd:sshd-pam
28 | org.bouncycastle:bcprov-jdk15on
29 | org.bouncycastle:bcpkix-jdk15on
30 | org.slf4j:slf4j-api
31 | org.slf4j:slf4j-jdk14
32 | org.codehaus.groovy:groovy-all
33 |
34 | false
35 | true
36 | false
37 | /lib
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/main/java/org/vertx/mods/CRaSHBusMod.java:
--------------------------------------------------------------------------------
1 | package org.vertx.mods;
2 |
3 | import org.crsh.shell.Shell;
4 | import org.crsh.shell.ShellFactory;
5 | import org.vertx.java.busmods.BusModBase;
6 | import org.vertx.java.core.Handler;
7 | import org.vertx.java.core.eventbus.Message;
8 | import org.vertx.java.core.json.JsonArray;
9 | import org.vertx.java.core.json.JsonObject;
10 |
11 | import java.util.LinkedList;
12 |
13 | /** @author Julien Viet */
14 | public class CRaSHBusMod extends BusModBase {
15 |
16 | /** . */
17 | private VertxPluginLifeCycle lifeCycle;
18 |
19 | @Override
20 | public void start() {
21 | try {
22 | ClassLoader loader = Thread.currentThread().getContextClassLoader();
23 | lifeCycle = new VertxPluginLifeCycle(loader, this);
24 | lifeCycle.start();
25 | getVertx().eventBus().registerHandler("crash.execute", new Handler>() {
26 | @Override
27 | public void handle(Message event) {
28 | JsonArray requestsArray = event.body().getArray("requests");
29 | String replyTo = event.body().getString("replyTo");
30 | LinkedList requests = new LinkedList<>();
31 | for (Object o : requestsArray) {
32 | requests.add(o.toString());
33 | }
34 | ShellFactory factory = lifeCycle.getContext().getPlugin(ShellFactory.class);
35 | Shell shell = factory.create(null);
36 | VertxProcessContext context = new VertxProcessContext(
37 | getVertx().eventBus(),
38 | shell,
39 | requests,
40 | replyTo);
41 | context.run();
42 | }
43 | });
44 | }
45 | catch (Exception e) {
46 | throw new RuntimeException("Could not start mod", e);
47 | }
48 | }
49 |
50 | @Override
51 | public void stop() {
52 | if (lifeCycle != null) {
53 | lifeCycle.stop();
54 | lifeCycle = null;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/org/vertx/mods/Format.java:
--------------------------------------------------------------------------------
1 | package org.vertx.mods;
2 |
3 | import org.vertx.java.core.Handler;
4 | import org.vertx.java.core.eventbus.EventBus;
5 | import org.vertx.java.core.eventbus.Message;
6 | import org.vertx.java.core.json.JsonObject;
7 |
8 | /** @author Julien Viet */
9 | public enum Format {
10 |
11 | JSON() {
12 |
13 | @Override
14 | public void publish(EventBus bus, String address, String value) {
15 | JsonObject json = VertxCommand.parseJson(value);
16 | bus.publish(address, json);
17 | }
18 |
19 | @Override
20 | public void send(EventBus bus, String address, String value, final Handler> replyHandler) {
21 | JsonObject json = VertxCommand.parseJson(value);
22 | if (replyHandler != null) {
23 | bus.send(address, json, new Handler>() {
24 | public void handle(Message event) {
25 | replyHandler.handle(event);
26 | }
27 | });
28 | } else {
29 | bus.send(address, json);
30 | }
31 | }
32 | },
33 |
34 | STRING() {
35 |
36 | @Override
37 | public void publish(EventBus bus, String address, String value) {
38 | bus.publish(address, value);
39 | }
40 |
41 | @Override
42 | public void send(EventBus bus, String address, String value, final Handler> replyHandler) {
43 | if (replyHandler != null) {
44 | bus.send(address, value, new Handler>() {
45 | public void handle(Message event) {
46 | replyHandler.handle(event);
47 | }
48 | });
49 | } else {
50 | bus.send(address, value);
51 | }
52 | }
53 | };
54 |
55 | public abstract void publish(EventBus bus, String address, String value);
56 |
57 | public abstract void send(EventBus bus, String address, String value, Handler> replyHandler);
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/vertx/mods/VertxCommand.java:
--------------------------------------------------------------------------------
1 | package org.vertx.mods;
2 |
3 | import org.crsh.command.ScriptException;
4 | import org.crsh.groovy.GroovyCommand;
5 | import org.vertx.java.core.Vertx;
6 | import org.vertx.java.core.json.DecodeException;
7 | import org.vertx.java.core.json.JsonObject;
8 | import org.vertx.java.platform.Container;
9 | import org.vertx.java.platform.impl.DefaultContainer;
10 | import org.vertx.java.platform.impl.DefaultPlatformManager;
11 | import org.vertx.java.platform.impl.Deployment;
12 | import org.vertx.java.platform.impl.PlatformManagerInternal;
13 |
14 | import java.lang.reflect.Field;
15 | import java.util.Collections;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | /** @author Julien Viet */
20 | public class VertxCommand extends GroovyCommand {
21 |
22 | protected final Vertx getVertx() {
23 | return (Vertx)context.getAttributes().get("vertx");
24 | }
25 |
26 | protected final Container getContainer() {
27 | return (Container)context.getAttributes().get("container");
28 | }
29 |
30 | protected final PlatformManagerInternal getManager() {
31 | try {
32 | Container container = getContainer();
33 | Field f = DefaultContainer.class.getDeclaredField("mgr");
34 | f.setAccessible(true);
35 | return (PlatformManagerInternal)f.get(container);
36 | }
37 | catch (Exception e) {
38 | e.printStackTrace();
39 | throw new ScriptException("Could not access verticle manager");
40 | }
41 | }
42 |
43 | protected final Map getDeployments() {
44 | try {
45 | PlatformManagerInternal mgr = getManager();
46 | Field d = DefaultPlatformManager.class.getDeclaredField("deployments");
47 | d.setAccessible(true);
48 | return Collections.unmodifiableMap((Map)d.get(mgr));
49 | }
50 | catch (Exception e) {
51 | throw new ScriptException("Could not access deployments");
52 | }
53 | }
54 |
55 | public static String join(List parts) {
56 | StringBuilder sb = new StringBuilder();
57 | for (String part : parts) {
58 | sb.append(part);
59 | }
60 | return sb.toString();
61 | }
62 |
63 | public static JsonObject parseJson(List parts) throws ScriptException {
64 | return parseJson(join(parts));
65 | }
66 |
67 | public static JsonObject parseJson(String s) throws ScriptException {
68 | try {
69 | return new JsonObject(s);
70 | }
71 | catch (DecodeException ignore) {
72 | throw new ScriptException("Invalid JSON:" + s);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/org/vertx/mods/VertxPluginLifeCycle.java:
--------------------------------------------------------------------------------
1 | package org.vertx.mods;
2 |
3 | import org.crsh.plugin.PluginContext;
4 | import org.crsh.plugin.PluginLifeCycle;
5 | import org.crsh.plugin.ServiceLoaderDiscovery;
6 | import org.crsh.vfs.FS;
7 | import org.crsh.vfs.Path;
8 | import org.vertx.java.core.json.JsonArray;
9 | import org.vertx.java.core.json.JsonObject;
10 | import org.vertx.java.platform.Verticle;
11 |
12 | import java.io.File;
13 | import java.util.Collections;
14 | import java.util.HashMap;
15 | import java.util.Properties;
16 |
17 | /** @author Julien Viet */
18 | class VertxPluginLifeCycle extends PluginLifeCycle {
19 |
20 | /** . */
21 | private final ClassLoader loader;
22 |
23 | /** . */
24 | private final Verticle verticle;
25 |
26 | /** . */
27 | private final PluginContext context;
28 |
29 | VertxPluginLifeCycle(ClassLoader loader, Verticle verticle) throws Exception {
30 |
31 | //
32 | HashMap attributes = new HashMap();
33 | attributes.put("vertx", verticle.getVertx());
34 | attributes.put("container", verticle.getContainer());
35 |
36 | //
37 | JsonObject verticleConfig = verticle.getContainer().config();
38 |
39 | // Build configuration
40 | Properties config = new Properties();
41 | for (String s : verticleConfig.getFieldNames()) {
42 | if (s.startsWith("crash.")) {
43 | String value = "" + verticleConfig.getField(s);
44 | config.put(s, value);
45 | }
46 | }
47 | setConfig(config);
48 |
49 | //
50 | FS confFS = new FS();
51 |
52 | //
53 | FS cmdFS = new FS();
54 | cmdFS.mount(loader, Path.get("/crash/commands/"));
55 | Object o = verticleConfig.getField("cmd");
56 | if (o instanceof String) {
57 | cmdFS.mount(new File((String)o));
58 | } else if (o instanceof JsonArray) {
59 | JsonArray array = (JsonArray)o;
60 | for (Object e : array) {
61 | if (e instanceof String) {
62 | cmdFS.mount(new File((String)e));
63 | }
64 | }
65 | }
66 |
67 | //
68 | PluginContext context = new PluginContext(
69 | new ServiceLoaderDiscovery(loader),
70 | Collections.unmodifiableMap(attributes),
71 | cmdFS,
72 | confFS,
73 | loader);
74 |
75 | //
76 | this.loader = loader;
77 | this.verticle = verticle;
78 | this.context = context;
79 | }
80 |
81 | void start() {
82 | context.refresh();
83 | start(context);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/org/vertx/mods/VertxProcessContext.java:
--------------------------------------------------------------------------------
1 | package org.vertx.mods;
2 |
3 | import org.crsh.shell.Shell;
4 | import org.crsh.shell.ShellProcess;
5 | import org.crsh.shell.ShellProcessContext;
6 | import org.crsh.shell.ShellResponse;
7 | import org.crsh.text.ScreenBuffer;
8 | import org.crsh.text.Screenable;
9 | import org.crsh.text.Style;
10 | import org.crsh.text.Format;
11 | import org.vertx.java.core.eventbus.EventBus;
12 |
13 | import java.io.IOException;
14 | import java.util.LinkedList;
15 |
16 | /**
17 | * @author Julien Viet
18 | */
19 | public class VertxProcessContext implements ShellProcessContext {
20 |
21 | /** . */
22 | private final ScreenBuffer screen = new ScreenBuffer();
23 |
24 | /** . */
25 | private final LinkedList requests;
26 |
27 | /** . */
28 | private final Shell shell;
29 |
30 | /** . */
31 | private final String replyTo;
32 |
33 | /** . */
34 | private final EventBus bus;
35 |
36 | public VertxProcessContext(EventBus bus, Shell shell, LinkedList requests, String replyTo) {
37 | this.bus = bus;
38 | this.replyTo = replyTo;
39 | this.shell = shell;
40 | this.requests = requests;
41 | }
42 |
43 | public void run() {
44 | if (requests.size() > 0) {
45 | ShellProcess process = shell.createProcess(requests.peekFirst());
46 | process.execute(this);
47 | }
48 | }
49 |
50 | @Override
51 | public void end(ShellResponse response) {
52 |
53 | // Remove what we executed
54 | String request = requests.removeFirst();
55 |
56 | //
57 | if (replyTo != null) {
58 | try {
59 | // For now render to text
60 | StringBuilder buffer = new StringBuilder();
61 |
62 | //
63 | buffer.append(request).append(":\n");
64 |
65 | // For now render to text
66 | screen.format(Format.TEXT, buffer);
67 |
68 | // Append response message if any
69 | String msg = response.getMessage();
70 | if (msg != null) {
71 | buffer.append(msg);
72 | }
73 |
74 | // Publish message
75 | bus.publish(replyTo, buffer.toString());
76 | }
77 | catch (IOException e) {
78 | e.printStackTrace();
79 | }
80 | }
81 |
82 | // Should be a "reset" but for now we don't care about style
83 | screen.clear();
84 |
85 | // Execute next if any
86 | run();
87 | }
88 |
89 | @Override
90 | public boolean takeAlternateBuffer() throws IOException {
91 | return false;
92 | }
93 |
94 | @Override
95 | public boolean releaseAlternateBuffer() throws IOException {
96 | return false;
97 | }
98 |
99 | @Override
100 | public String getProperty(String propertyName) {
101 | return null;
102 | }
103 |
104 | @Override
105 | public String readLine(String msg, boolean echo) throws IOException, InterruptedException, IllegalStateException {
106 | return null;
107 | }
108 |
109 | @Override
110 | public int getWidth() {
111 | return 80;
112 | }
113 |
114 | @Override
115 | public int getHeight() {
116 | return 40;
117 | }
118 |
119 | @Override
120 | public Appendable append(char c) throws IOException {
121 | screen.append(c);
122 | return this;
123 | }
124 |
125 | @Override
126 | public Appendable append(CharSequence s) throws IOException {
127 | screen.append(s);
128 | return this;
129 | }
130 |
131 | @Override
132 | public Appendable append(CharSequence csq, int start, int end) throws IOException {
133 | screen.append(csq, start, end);
134 | return null;
135 | }
136 |
137 | @Override
138 | public Screenable append(Style style) throws IOException {
139 | screen.append(style);
140 | return this;
141 | }
142 |
143 | @Override
144 | public Screenable cls() throws IOException {
145 | screen.cls();
146 | return this;
147 | }
148 |
149 | @Override
150 | public void flush() throws IOException {
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/resources/crash/commands/vertx/bus.groovy:
--------------------------------------------------------------------------------
1 | package crash.commands.vertx
2 |
3 | import org.crsh.cli.Argument
4 | import org.crsh.cli.Command
5 | import org.crsh.cli.Option
6 | import org.crsh.cli.Required
7 | import org.crsh.cli.Usage
8 | import org.vertx.java.core.Handler
9 | import org.vertx.java.core.eventbus.EventBus
10 | import org.vertx.java.core.eventbus.Message
11 | import org.vertx.mods.Format
12 | import org.vertx.mods.VertxCommand
13 |
14 | import java.util.concurrent.atomic.AtomicReference
15 |
16 | @Usage("interact with the vert.x event bus")
17 | public class bus extends VertxCommand {
18 |
19 | @Usage("send a message on the bus")
20 | @Command
21 | public void send(
22 | @Usage("the address to send to")
23 | @Argument(name = "address")
24 | @Required String address,
25 | @Usage("the message format")
26 | @Option(names = ["f","format"])
27 | Format format,
28 | @Usage("wait for a reply and publish it on the console")
29 | @Option(names= ["r","reply"])
30 | Boolean reply,
31 | @Usage("the message")
32 | @Argument(name = "message", unquote = false)
33 | @Required List parts) {
34 | String value = join(parts);
35 | EventBus bus = getVertx().eventBus();
36 | if (reply) {
37 | final AtomicReference responseRef = new AtomicReference(null);
38 | def replyHandler = new Handler>() {
39 | void handle(Message message) {
40 | synchronized (responseRef) {
41 | responseRef.set(message);
42 | responseRef.notifyAll();
43 | }
44 | }
45 | }
46 | (format?:Format.STRING).send(bus, address, value, replyHandler);
47 | synchronized (responseRef) {
48 | if (responseRef.get() == null) {
49 | try {
50 | responseRef.wait();
51 | }
52 | catch (InterruptedException cancelled) {
53 | }
54 | }
55 | }
56 | if (responseRef.get() != null) {
57 | Message