├── .editorconfig ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── LICENSE-aslv20.html ├── README.md ├── docs ├── apidocs │ ├── allclasses-frame.html │ ├── allclasses-index.html │ ├── allclasses-noframe.html │ ├── allclasses.html │ ├── allpackages-index.html │ ├── com │ │ └── julienviet │ │ │ └── childprocess │ │ │ ├── Process.html │ │ │ ├── ProcessBuilder.html │ │ │ ├── ProcessOptions.html │ │ │ ├── StartException.html │ │ │ ├── StreamInput.html │ │ │ ├── StreamOutput.html │ │ │ ├── class-use │ │ │ ├── Process.html │ │ │ ├── ProcessBuilder.html │ │ │ ├── ProcessOptions.html │ │ │ ├── StartException.html │ │ │ ├── StreamInput.html │ │ │ └── StreamOutput.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ ├── package-tree.html │ │ │ └── package-use.html │ ├── constant-values.html │ ├── deprecated-list.html │ ├── element-list │ ├── help-doc.html │ ├── index-all.html │ ├── index.html │ ├── jquery-ui.overrides.css │ ├── jquery │ │ ├── external │ │ │ └── jquery │ │ │ │ └── jquery.js │ │ ├── jquery-3.6.1.min.js │ │ ├── jquery-ui.min.css │ │ ├── jquery-ui.min.js │ │ ├── jszip-utils │ │ │ └── dist │ │ │ │ ├── jszip-utils-ie.js │ │ │ │ ├── jszip-utils-ie.min.js │ │ │ │ ├── jszip-utils.js │ │ │ │ └── jszip-utils.min.js │ │ └── jszip │ │ │ └── dist │ │ │ ├── jszip.js │ │ │ └── jszip.min.js │ ├── member-search-index.js │ ├── member-search-index.zip │ ├── overview-tree.html │ ├── package-list │ ├── package-search-index.js │ ├── package-search-index.zip │ ├── resources │ │ ├── glass.png │ │ └── x.png │ ├── script.js │ ├── search.js │ ├── serialized-form.html │ ├── stylesheet.css │ ├── type-search-index.js │ └── type-search-index.zip └── guide │ └── java │ └── index.md ├── pom.xml └── src ├── main ├── asciidoc │ └── dataobjects.adoc ├── docs │ └── index.md ├── generated │ └── io │ │ └── reactiverse │ │ └── childprocess │ │ └── ProcessOptionsConverter.java └── java │ ├── examples │ └── Examples.java │ └── io │ └── reactiverse │ └── childprocess │ ├── Process.java │ ├── ProcessBuilder.java │ ├── ProcessOptions.java │ ├── StartException.java │ ├── StreamInput.java │ ├── StreamOutput.java │ ├── impl │ ├── ProcessBuilderImpl.java │ ├── ProcessImpl.java │ └── ProcessStreamInput.java │ └── package-info.java └── test └── java ├── EchoStderr.java ├── EchoStdout.java ├── ExitCode.java ├── PrintCwd.java ├── PrintEnv.java ├── Shutdown.java ├── StdoutLongSequence.java └── io └── reactiverse └── childprocess ├── Main.java └── SpawnTest.java /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | [**/examples/**.java] 12 | max_line_length = 80 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | jekyll/apidocs 2 | jekyll/yardoc 3 | jekyll/guide 4 | jekyll/.* 5 | jekyll/_site 6 | jekyll/jsdoc 7 | .vertx 8 | .DS_Store 9 | .gradle 10 | .idea 11 | .classpath 12 | .project 13 | .settings 14 | .yardoc 15 | .yardopts 16 | build 17 | target 18 | out 19 | *.iml 20 | *.ipr 21 | *.iws 22 | test-output 23 | Scratch.java 24 | ScratchTest.java 25 | test-results 26 | test-tmp 27 | *.class 28 | ScratchPad.java 29 | src/main/resources/ext-js/*.js 30 | src/main/java/io/vertx/java/**/*.java 31 | src/main/groovy/io/vertx/groovy/**/*.groovy 32 | *.swp 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Child Process extension for Vert.x 2 | 3 | [![childprocess-vertx-ext](https://github.com/vietj/childprocess-vertx-ext/actions/workflows/ci.yml/badge.svg)](https://github.com/vietj/childprocess-vertx-ext/actions/workflows/ci.yml) 4 | 5 | Spawn child processes from Vert.x. 6 | 7 | Based on https://github.com/brettwooldridge/NuProcess _Low-overhead, non-blocking I/O, external Process implementation for Java_. 8 | 9 | ## What for ? 10 | 11 | [Vert.x 5](http://vertx.io) 12 | 13 | ## Using Child Process 14 | 15 | To use Child Process, add the following dependency to the _dependencies_ section of your build descriptor: 16 | 17 | * Maven (in your `pom.xml`): 18 | 19 | ```xml 20 | 21 | io.reactiverse 22 | childprocess-vertx-ext 23 | 2.0.0 24 | 25 | ``` 26 | 27 | * Gradle (in your `build.gradle` file): 28 | 29 | ```groovy 30 | dependencies { 31 | compile 'io.reactiverse:childprocess-vertx-ext:2.0.0' 32 | } 33 | ``` 34 | 35 | Spawn child processes from Vert.x: 36 | 37 | ```java 38 | Process 39 | .create(vertx, "cat") 40 | .startHandler(process -> { 41 | process.exitHandler(code -> { 42 | System.out.println("Process exited: " + code); 43 | }); 44 | process.stdout().handler(buf -> { 45 | System.out.println("Process wrote: " + buf); 46 | }); 47 | StreamOutput stdin = process.stdin(); 48 | stdin.write(Buffer.buffer("hello")); 49 | stdin.close(); 50 | }).start(); 51 | ``` 52 | 53 | ## Web-site docs 54 | 55 | * [Java docs](http://www.julienviet.com/childprocess-vertx-ext/guide/java/index.html) 56 | 57 | ## Snapshots 58 | 59 | Use the dependency 60 | 61 | ```xml 62 | 63 | io.reactiverse 64 | childprocess-vertx-ext 65 | 2.0.0 66 | 67 | ``` 68 | 69 | Snapshots are deployed in Sonatype OSS repository: TBD. 70 | 71 | ## License 72 | 73 | Apache License - Version 2.0 74 | 75 | ## Documentation 76 | 77 | The online and published documentation is in `/docs` and is served by GitHub pages with Jekyll. 78 | 79 | You can find the actual guide source in [src/main/docs/index.md](src/main/docs/index.md). At compilation time, this 80 | source generates the `jekyll/guide/java/index.md`. 81 | 82 | The current documentation is in `/jekyll` and can be preview using Docker and your browser 83 | 84 | * generate the documentation 85 | ** `mvn compile` to generate `jekyll/guide/java/index.md` 86 | ** `mvn site` to generate the javadoc in `jekyll/apidocs` 87 | * run Jekyll 88 | ** `cd jekyll` 89 | ** `docker-compose up` 90 | * open your browser at http://localhost:4000 91 | -------------------------------------------------------------------------------- /docs/apidocs/allclasses-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | All Classes (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 |

All Classes

14 |
15 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/apidocs/allclasses-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | All Classes (Child Process extension for Vert.x 2.0.0-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 40 | 43 |
44 | 100 |
101 |
102 |
103 |

All Classes

104 |
105 |
106 | 149 |
150 |
151 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /docs/apidocs/allclasses-noframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | All Classes (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 |

All Classes

14 |
15 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/apidocs/allclasses.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | All Classes (Child Process extension for Vert.x 2.0.0-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 |
23 |

All Classes

24 |
25 | 33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/apidocs/allpackages-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | All Packages (Child Process extension for Vert.x 2.0.0-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 34 | 37 |
38 | 94 |
95 |
96 |
97 |

All Packages

98 |
99 |
100 | 117 |
118 |
119 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/ProcessBuilder.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ProcessBuilder (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 29 | 32 | 33 |
34 | 35 | 36 |
Skip navigation links
37 | 38 | 39 | 40 | 49 |
50 | 92 | 93 | 94 |
95 |
com.julienviet.childprocess
96 |

Interface ProcessBuilder

97 |
98 |
99 |
100 | 107 |
108 |
109 | 140 |
141 |
142 | 180 |
181 |
182 | 183 | 184 |
185 | 186 | 187 |
Skip navigation links
188 | 189 | 190 | 191 | 200 |
201 | 243 | 244 |

Copyright © 2023 Eclipse. All rights reserved.

245 | 246 | 247 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/class-use/Process.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Uses of Interface com.julienviet.childprocess.Process (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Uses of Interface
com.julienviet.childprocess.Process

74 |
75 |
76 | 118 |
119 | 120 |
121 | 122 | 123 |
Skip navigation links
124 | 125 | 126 | 127 | 136 |
137 | 164 | 165 |

Copyright © 2023 Eclipse. All rights reserved.

166 | 167 | 168 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/class-use/ProcessBuilder.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Uses of Interface com.julienviet.childprocess.ProcessBuilder (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Uses of Interface
com.julienviet.childprocess.ProcessBuilder

74 |
75 |
76 | 134 |
135 | 136 |
137 | 138 | 139 |
Skip navigation links
140 | 141 | 142 | 143 | 152 |
153 | 180 | 181 |

Copyright © 2023 Eclipse. All rights reserved.

182 | 183 | 184 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/class-use/ProcessOptions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Uses of Class com.julienviet.childprocess.ProcessOptions (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Uses of Class
com.julienviet.childprocess.ProcessOptions

74 |
75 |
76 | 145 |
146 | 147 |
148 | 149 | 150 |
Skip navigation links
151 | 152 | 153 | 154 | 163 |
164 | 191 | 192 |

Copyright © 2023 Eclipse. All rights reserved.

193 | 194 | 195 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/class-use/StartException.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Uses of Class com.julienviet.childprocess.StartException (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Uses of Class
com.julienviet.childprocess.StartException

74 |
75 |
No usage of io.reactiverse.childprocess.StartException
76 | 77 |
78 | 79 | 80 |
Skip navigation links
81 | 82 | 83 | 84 | 93 |
94 | 121 | 122 |

Copyright © 2023 Eclipse. All rights reserved.

123 | 124 | 125 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/class-use/StreamInput.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Uses of Interface com.julienviet.childprocess.StreamInput (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Uses of Interface
com.julienviet.childprocess.StreamInput

74 |
75 |
76 | 122 |
123 | 124 |
125 | 126 | 127 |
Skip navigation links
128 | 129 | 130 | 131 | 140 |
141 | 168 | 169 |

Copyright © 2023 Eclipse. All rights reserved.

170 | 171 | 172 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/class-use/StreamOutput.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Uses of Interface com.julienviet.childprocess.StreamOutput (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Uses of Interface
com.julienviet.childprocess.StreamOutput

74 |
75 |
76 | 112 |
113 | 114 |
115 | 116 | 117 |
Skip navigation links
118 | 119 | 120 | 121 | 130 |
131 | 158 | 159 |

Copyright © 2023 Eclipse. All rights reserved.

160 | 161 | 162 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | com.julienviet.childprocess (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 |

com.julienviet.childprocess

14 |
15 |

Interfaces

16 | 22 |

Classes

23 | 26 |

Exceptions

27 | 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/package-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | com.julienviet.childprocess (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Package com.julienviet.childprocess

74 |
75 |
76 | 143 |
144 | 145 |
146 | 147 | 148 |
Skip navigation links
149 | 150 | 151 | 152 | 161 |
162 | 189 | 190 |

Copyright © 2023 Eclipse. All rights reserved.

191 | 192 | 193 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/package-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | com.julienviet.childprocess Class Hierarchy (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Hierarchy For Package com.julienviet.childprocess

74 |
75 |
76 |

Class Hierarchy

77 | 93 |

Interface Hierarchy

94 | 108 |
109 | 110 |
111 | 112 | 113 |
Skip navigation links
114 | 115 | 116 | 117 | 126 |
127 | 154 | 155 |

Copyright © 2023 Eclipse. All rights reserved.

156 | 157 | 158 | -------------------------------------------------------------------------------- /docs/apidocs/com/julienviet/childprocess/package-use.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Uses of Package com.julienviet.childprocess (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Uses of Package
com.julienviet.childprocess

74 |
75 |
76 | 113 |
114 | 115 |
116 | 117 | 118 |
Skip navigation links
119 | 120 | 121 | 122 | 131 |
132 | 159 | 160 |

Copyright © 2023 Eclipse. All rights reserved.

161 | 162 | 163 | -------------------------------------------------------------------------------- /docs/apidocs/constant-values.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Constant Field Values (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Constant Field Values

74 |

Contents

75 |
76 | 77 |
78 | 79 | 80 |
Skip navigation links
81 | 82 | 83 | 84 | 93 |
94 | 121 | 122 |

Copyright © 2023 Eclipse. All rights reserved.

123 | 124 | 125 | -------------------------------------------------------------------------------- /docs/apidocs/deprecated-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Deprecated List (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Deprecated API

74 |

Contents

75 |
76 | 77 |
78 | 79 | 80 |
Skip navigation links
81 | 82 | 83 | 84 | 93 |
94 | 121 | 122 |

Copyright © 2023 Eclipse. All rights reserved.

123 | 124 | 125 | -------------------------------------------------------------------------------- /docs/apidocs/element-list: -------------------------------------------------------------------------------- 1 | com.julienviet.childprocess 2 | -------------------------------------------------------------------------------- /docs/apidocs/help-doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | API Help (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 |
Skip navigation links
31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

How This API Document Is Organized

74 |
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
75 |
76 |
77 | 176 | This help file applies to API documentation generated using the standard doclet.
177 | 178 |
179 | 180 | 181 |
Skip navigation links
182 | 183 | 184 | 185 | 194 |
195 | 222 | 223 |

Copyright © 2023 Eclipse. All rights reserved.

224 | 225 | 226 | -------------------------------------------------------------------------------- /docs/apidocs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Child Process extension for Vert.x 2.0.0 API 8 | 61 | 62 | 63 | 64 | 65 | 66 | <noscript> 67 | <div>JavaScript is disabled on your browser.</div> 68 | </noscript> 69 | <h2>Frame Alert</h2> 70 | <p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="com/julienviet/childprocess/package-summary.html">Non-frame version</a>.</p> 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /docs/apidocs/jquery-ui.overrides.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | 26 | .ui-state-active, 27 | .ui-widget-content .ui-state-active, 28 | .ui-widget-header .ui-state-active, 29 | a.ui-button:active, 30 | .ui-button:active, 31 | .ui-button.ui-state-active:hover { 32 | /* Overrides the color of selection used in jQuery UI */ 33 | background: #F8981D; 34 | border: 1px solid #F8981D; 35 | } 36 | -------------------------------------------------------------------------------- /docs/apidocs/jquery/jquery-ui.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.13.1 - 2022-05-12 2 | * http://jqueryui.com 3 | * Includes: core.css, autocomplete.css, menu.css 4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 | 6 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;-ms-filter:"alpha(opacity=0)"}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0} -------------------------------------------------------------------------------- /docs/apidocs/jquery/jszip-utils/dist/jszip-utils-ie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | JSZipUtils - A collection of cross-browser utilities to go along with JSZip. 4 | 5 | 6 | (c) 2014 Stuart Knightley, David Duponchel 7 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. 8 | 9 | */ 10 | ;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\r\n"+ 18 | "\r\n"; 32 | 33 | // inject VBScript 34 | document.write(IEBinaryToArray_ByteStr_Script); 35 | 36 | global.JSZipUtils._getBinaryFromXHR = function (xhr) { 37 | var binary = xhr.responseBody; 38 | var byteMapping = {}; 39 | for ( var i = 0; i < 256; i++ ) { 40 | for ( var j = 0; j < 256; j++ ) { 41 | byteMapping[ String.fromCharCode( i + (j << 8) ) ] = 42 | String.fromCharCode(i) + String.fromCharCode(j); 43 | } 44 | } 45 | var rawBytes = IEBinaryToArray_ByteStr(binary); 46 | var lastChr = IEBinaryToArray_ByteStr_Last(binary); 47 | return rawBytes.replace(/[\s\S]/g, function( match ) { 48 | return byteMapping[match]; 49 | }) + lastChr; 50 | }; 51 | 52 | // enforcing Stuk's coding style 53 | // vim: set shiftwidth=4 softtabstop=4: 54 | 55 | },{}]},{},[1]) 56 | ; 57 | -------------------------------------------------------------------------------- /docs/apidocs/jquery/jszip-utils/dist/jszip-utils-ie.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | JSZipUtils - A collection of cross-browser utilities to go along with JSZip. 4 | 5 | 6 | (c) 2014 Stuart Knightley, David Duponchel 7 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. 8 | 9 | */ 10 | !function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g\r\n";document.write(b),a.JSZipUtils._getBinaryFromXHR=function(a){for(var b=a.responseBody,c={},d=0;256>d;d++)for(var e=0;256>e;e++)c[String.fromCharCode(d+(e<<8))]=String.fromCharCode(d)+String.fromCharCode(e);var f=IEBinaryToArray_ByteStr(b),g=IEBinaryToArray_ByteStr_Last(b);return f.replace(/[\s\S]/g,function(a){return c[a]})+g}},{}]},{},[1]); 11 | -------------------------------------------------------------------------------- /docs/apidocs/jquery/jszip-utils/dist/jszip-utils.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | JSZipUtils - A collection of cross-browser utilities to go along with JSZip. 4 | 5 | 6 | (c) 2014 Stuart Knightley, David Duponchel 7 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. 8 | 9 | */ 10 | !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 5 | 6 | (c) 2014 Stuart Knightley, David Duponchel 7 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. 8 | 9 | */ 10 | !function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZipUtils=a():"undefined"!=typeof global?global.JSZipUtils=a():"undefined"!=typeof self&&(self.JSZipUtils=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g, ProcessOptions)","url":"create(io.vertx.core.Vertx,java.lang.String,java.util.List,com.julienviet.childprocess.ProcessOptions)"},{"p":"com.julienviet.childprocess","c":"Process","l":"create(Vertx, String, List)","url":"create(io.vertx.core.Vertx,java.lang.String,java.util.List)"},{"p":"com.julienviet.childprocess","c":"Process","l":"create(Vertx, String, ProcessOptions)","url":"create(io.vertx.core.Vertx,java.lang.String,com.julienviet.childprocess.ProcessOptions)"},{"p":"com.julienviet.childprocess","c":"Process","l":"create(Vertx, String)","url":"create(io.vertx.core.Vertx,java.lang.String)"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"DEFAULT_ENV"},{"p":"com.julienviet.childprocess","c":"StreamOutput","l":"drainHandler(Handler)","url":"drainHandler(io.vertx.core.Handler)"},{"p":"com.julienviet.childprocess","c":"StreamOutput","l":"end()"},{"p":"com.julienviet.childprocess","c":"StreamInput","l":"endHandler(Handler)","url":"endHandler(io.vertx.core.Handler)"},{"p":"com.julienviet.childprocess","c":"Process","l":"env()"},{"p":"com.julienviet.childprocess","c":"StreamInput","l":"exceptionHandler(Handler)","url":"exceptionHandler(io.vertx.core.Handler)"},{"p":"com.julienviet.childprocess","c":"StreamOutput","l":"exceptionHandler(Handler)","url":"exceptionHandler(io.vertx.core.Handler)"},{"p":"com.julienviet.childprocess","c":"Process","l":"exitHandler(Handler)","url":"exitHandler(io.vertx.core.Handler)"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"getCwd()"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"getEnv()"},{"p":"com.julienviet.childprocess","c":"StreamInput","l":"handler(Handler)","url":"handler(io.vertx.core.Handler)"},{"p":"com.julienviet.childprocess","c":"Process","l":"isRunning()"},{"p":"com.julienviet.childprocess","c":"Process","l":"kill()"},{"p":"com.julienviet.childprocess","c":"Process","l":"kill(boolean)"},{"p":"com.julienviet.childprocess","c":"Process","l":"pid()"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"ProcessOptions()","url":"%3Cinit%3E()"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"ProcessOptions(JsonObject)","url":"%3Cinit%3E(io.vertx.core.json.JsonObject)"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"ProcessOptions(ProcessOptions)","url":"%3Cinit%3E(com.julienviet.childprocess.ProcessOptions)"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"setCwd(String)","url":"setCwd(java.lang.String)"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"setEnv(Map)","url":"setEnv(java.util.Map)"},{"p":"com.julienviet.childprocess","c":"StreamOutput","l":"setWriteQueueMaxSize(int)"},{"p":"com.julienviet.childprocess","c":"ProcessBuilder","l":"start()"},{"p":"com.julienviet.childprocess","c":"StartException","l":"StartException(int, Buffer, Buffer)","url":"%3Cinit%3E(int,io.vertx.core.buffer.Buffer,io.vertx.core.buffer.Buffer)"},{"p":"com.julienviet.childprocess","c":"ProcessBuilder","l":"startHandler(Handler)","url":"startHandler(io.vertx.core.Handler)"},{"p":"com.julienviet.childprocess","c":"Process","l":"stderr()"},{"p":"com.julienviet.childprocess","c":"Process","l":"stdin()"},{"p":"com.julienviet.childprocess","c":"Process","l":"stdout()"},{"p":"com.julienviet.childprocess","c":"ProcessOptions","l":"toJson()"},{"p":"com.julienviet.childprocess","c":"StreamOutput","l":"write(Buffer)","url":"write(io.vertx.core.buffer.Buffer)"}] -------------------------------------------------------------------------------- /docs/apidocs/member-search-index.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vietj/childprocess-vertx-ext/ca532a8849ad199bdbf6f5e63f0834a882891502/docs/apidocs/member-search-index.zip -------------------------------------------------------------------------------- /docs/apidocs/overview-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class Hierarchy (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Hierarchy For All Packages

74 | Package Hierarchies: 75 | 78 |
79 |
80 |

Class Hierarchy

81 | 97 |

Interface Hierarchy

98 |
    99 |
  • com.julienviet.childprocess.Process
  • 100 |
  • com.julienviet.childprocess.ProcessBuilder
  • 101 |
  • io.vertx.core.streams.StreamBase 102 |
      103 |
    • com.julienviet.childprocess.StreamInput
    • 104 |
    • com.julienviet.childprocess.StreamOutput
    • 105 |
    • io.vertx.core.streams.WriteStream<T> 106 | 109 |
    • 110 |
    111 |
  • 112 |
113 |
114 | 115 |
116 | 117 | 118 | 119 | 120 | 121 | 122 | 131 |
132 | 159 | 160 |

Copyright © 2023 Eclipse. All rights reserved.

161 | 162 | 163 | -------------------------------------------------------------------------------- /docs/apidocs/package-list: -------------------------------------------------------------------------------- 1 | com.julienviet.childprocess 2 | -------------------------------------------------------------------------------- /docs/apidocs/package-search-index.js: -------------------------------------------------------------------------------- 1 | packageSearchIndex = [{"l":"All Packages","url":"allpackages-index.html"},{"l":"com.julienviet.childprocess"}] -------------------------------------------------------------------------------- /docs/apidocs/package-search-index.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vietj/childprocess-vertx-ext/ca532a8849ad199bdbf6f5e63f0834a882891502/docs/apidocs/package-search-index.zip -------------------------------------------------------------------------------- /docs/apidocs/resources/glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vietj/childprocess-vertx-ext/ca532a8849ad199bdbf6f5e63f0834a882891502/docs/apidocs/resources/glass.png -------------------------------------------------------------------------------- /docs/apidocs/resources/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vietj/childprocess-vertx-ext/ca532a8849ad199bdbf6f5e63f0834a882891502/docs/apidocs/resources/x.png -------------------------------------------------------------------------------- /docs/apidocs/script.js: -------------------------------------------------------------------------------- 1 | function show(type) 2 | { 3 | count = 0; 4 | for (var key in methods) { 5 | var row = document.getElementById(key); 6 | if ((methods[key] & type) != 0) { 7 | row.style.display = ''; 8 | row.className = (count++ % 2) ? rowColor : altColor; 9 | } 10 | else 11 | row.style.display = 'none'; 12 | } 13 | updateTabs(type); 14 | } 15 | 16 | function updateTabs(type) 17 | { 18 | for (var value in tabs) { 19 | var sNode = document.getElementById(tabs[value][0]); 20 | var spanNode = sNode.firstChild; 21 | if (value == type) { 22 | sNode.className = activeTableTab; 23 | spanNode.innerHTML = tabs[value][1]; 24 | } 25 | else { 26 | sNode.className = tableTab; 27 | spanNode.innerHTML = "" + tabs[value][1] + ""; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/apidocs/serialized-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Serialized Form (Child Process extension for Vert.x 2.0.0 API) 8 | 9 | 10 | 11 | 12 | 13 | 23 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 43 |
44 | 71 | 72 |
73 |

Serialized Form

74 |
75 |
76 |
    77 |
  • 78 |

    Package com.julienviet.childprocess

    79 |
      80 |
    • 81 | 82 | 83 |

      Class io.reactiverse.childprocess.StartException extends Exception implements Serializable

      84 |
        85 |
      • 86 |

        Serialized Fields

        87 |
          88 |
        • 89 |

          exitCode

          90 |
          int exitCode
          91 |
        • 92 |
        • 93 |

          stdout

          94 |
          io.vertx.core.buffer.Buffer stdout
          95 |
        • 96 |
        • 97 |

          stdin

          98 |
          io.vertx.core.buffer.Buffer stdin
          99 |
        • 100 |
        101 |
      • 102 |
      103 |
    • 104 |
    105 |
  • 106 |
107 |
108 | 109 |
110 | 111 | 112 | 113 | 114 | 115 | 116 | 125 |
126 | 153 | 154 |

Copyright © 2023 Eclipse. All rights reserved.

155 | 156 | 157 | -------------------------------------------------------------------------------- /docs/apidocs/type-search-index.js: -------------------------------------------------------------------------------- 1 | typeSearchIndex = [{"l":"All Classes","url":"allclasses-index.html"},{"p":"com.julienviet.childprocess","l":"Process"},{"p":"com.julienviet.childprocess","l":"ProcessBuilder"},{"p":"com.julienviet.childprocess","l":"ProcessOptions"},{"p":"com.julienviet.childprocess","l":"StartException"},{"p":"com.julienviet.childprocess","l":"StreamInput"},{"p":"com.julienviet.childprocess","l":"StreamOutput"}] -------------------------------------------------------------------------------- /docs/apidocs/type-search-index.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vietj/childprocess-vertx-ext/ca532a8849ad199bdbf6f5e63f0834a882891502/docs/apidocs/type-search-index.zip -------------------------------------------------------------------------------- /docs/guide/java/index.md: -------------------------------------------------------------------------------- 1 | # Child Process extension for Vert.x 2 | 3 | Child Process is a Vert.x component for spawning OS child processes. 4 | 5 | * based on https://github.com/brettwooldridge/NuProcess _Low-overhead, non-blocking I/O, external Process implementation for Java_. 6 | * standard streams are fully non blocking 7 | * spawned process can be killed 8 | 9 | ## Using Child Process 10 | 11 | To use Child Process, add the following dependency to the _dependencies_ section of your build descriptor: 12 | 13 | * Maven (in your `pom.xml`): 14 | 15 | ```xml 16 | 17 | com.julienviet 18 | childprocess-vertx-ext 19 | 2.0.0 20 | 21 | ``` 22 | 23 | * Gradle (in your `build.gradle` file): 24 | 25 | ```java 26 | dependencies { 27 | compile 'com.julienviet:childprocess-vertx-ext:2.0.0' 28 | } 29 | ``` 30 | 31 | ## Spawning child processes 32 | 33 | You can spawn child processes with the [`Process.create`](../../apidocs/com/julienviet/childprocess/Process.html#create-io.vertx.core.Vertx-java.lang.String-) and [`start`](../../apidocs/com/julienviet/childprocess/ProcessBuilder.html#start--) methods: 34 | 35 | ```java 36 | ProcessBuilder processBuilder = Process.create(vertx, "ls"); 37 | 38 | // Start the process 39 | Future fut = processBuilder.start(); 40 | ``` 41 | 42 | the future returned by `start` completes when the process has started or failed 43 | 44 | you can give arguments to child processes 45 | 46 | ```java 47 | Process.create(vertx, "ls", Arrays.asList("-lh", "/usr")).start(); 48 | ``` 49 | 50 | by default child processes use the current process environment options, you can pass key-value pairs as new environment variables 51 | 52 | ```java 53 | Map env = new HashMap<>(); 54 | env.put("MY_VAR", "whatever"); 55 | Process.create(vertx, "ls", new ProcessOptions().setEnv(env)).start(); 56 | ``` 57 | 58 | [`Process.env`](../../apidocs/com/julienviet/childprocess/Process.html#env--) gives you the current process environment key-value pairs 59 | 60 | ```java 61 | ProcessOptions options = new ProcessOptions().setEnv(Process.env()); 62 | Process.create(vertx, "ls", options).start(); 63 | ``` 64 | 65 | By default, the child processes uses the current process _current working directory_, the 66 | [`setCwd`](../../apidocs/com/julienviet/childprocess/ProcessOptions.html#setCwd-java.lang.String-) option overrides it 67 | 68 | ```java 69 | ProcessOptions options = new ProcessOptions().setCwd("/some-dir"); 70 | Process.create(vertx, "ls", options).start(); 71 | ``` 72 | 73 | ## Interacting with child processes 74 | 75 | The child process streams are available as 76 | 77 | * [`stdin`](../../apidocs/com/julienviet/childprocess/Process.html#stdin--) 78 | * [`stdout`](../../apidocs/com/julienviet/childprocess/Process.html#stdout--) 79 | * [`stderr`](../../apidocs/com/julienviet/childprocess/Process.html#stderr--) 80 | 81 | ```java 82 | ProcessBuilder processBuilder = Process.create(vertx, "cat"); 83 | 84 | processBuilder.startHandler(process -> { 85 | process.stdout().handler(buff -> { 86 | System.out.println(buff.toString()); 87 | }); 88 | 89 | process.stdin().write(Buffer.buffer("Hello World")); 90 | }); 91 | 92 | processBuilder.start(); 93 | ``` 94 | 95 | Calling [`kill`](../../apidocs/com/julienviet/childprocess/Process.html#kill--) kills the child process, on POSIX it sends the 96 | `SIGTERM` signal. 97 | 98 | ```java 99 | Process 100 | .create(vertx, "cat") 101 | .startHandler(process -> { 102 | 103 | process.stdout().handler(buff -> { 104 | System.out.println(buff.toString()); 105 | }); 106 | 107 | process.stdin().write(Buffer.buffer("Hello World")); 108 | 109 | // Kill the process 110 | process.kill(); 111 | }) 112 | .start(); 113 | ``` 114 | 115 | Child processes can also be forcibly killed 116 | 117 | ```java 118 | Process 119 | .create(vertx, "cat") 120 | .startHandler(process -> { 121 | 122 | process.stdout().handler(buff -> { 123 | System.out.println(buff.toString()); 124 | }); 125 | 126 | process.stdin().write(Buffer.buffer("Hello World")); 127 | 128 | // Kill the process forcibly 129 | process.kill(true); 130 | 131 | }).start(); 132 | ``` 133 | 134 | ## Child process lifecycle 135 | 136 | You can be aware of the child process termination 137 | 138 | ```java 139 | Process 140 | .create(vertx, "sleep", Arrays.asList("2")) 141 | .startHandler(process -> { 142 | process.exitHandler(code -> { 143 | System.out.println("Child process exited with code: " + code); 144 | }); 145 | }) 146 | .start(); 147 | ``` -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | com.julienviet 24 | parent 25 | 1 26 | 27 | 28 | io.reactiverse 29 | childprocess-vertx-ext 30 | 2.0.2-SNAPSHOT 31 | 32 | Child Process extension for Vert.x 33 | https://github.com/reactiverse/childprocess-vertx-ext 34 | Spawn child processes from Vert.x 35 | 36 | 37 | 38 | The Apache Software License, Version 2.0 39 | http://www.apache.org/licenses/LICENSE-2.0.txt 40 | repo 41 | 42 | 43 | 44 | 45 | scm:git:git@github.com:reactiverse/childprocess-vertx-ext.git 46 | scm:git:git@github.com:reactiverse/childprocess-vertx-ext.git 47 | git@github.com:reactiverse/childprocess-vertx-ext.git 48 | 49 | 50 | 51 | 52 | Julien Viet 53 | julien@julienviet.com 54 | 55 | 56 | 57 | 58 | 5.0.0 59 | ${project.basedir}/src/main/generated 60 | ${project.basedir}/src/main/docs 61 | 62 | 63 | 64 | 65 | 66 | io.vertx 67 | vertx-dependencies 68 | ${vertx.version} 69 | pom 70 | import 71 | 72 | 73 | 74 | 75 | 76 | 77 | com.zaxxer 78 | nuprocess 79 | 3.0.0 80 | 81 | 82 | io.vertx 83 | vertx-core 84 | 85 | 86 | io.vertx 87 | vertx-codegen-api 88 | true 89 | 90 | 91 | io.vertx 92 | vertx-codegen-json 93 | true 94 | 95 | 96 | io.vertx 97 | vertx-docgen-api 98 | true 99 | 100 | 101 | io.vertx 102 | vertx-core 103 | test-jar 104 | test 105 | 106 | 107 | io.vertx 108 | vertx-unit 109 | test 110 | 111 | 112 | junit 113 | junit 114 | test 115 | 4.13.1 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | maven-compiler-plugin 125 | ${maven.compiler.plugin.version} 126 | 127 | 128 | default-compile 129 | 130 | ${project.basedir/src/main/generated} 131 | 132 | 133 | io.vertx 134 | vertx-codegen 135 | processor 136 | ${vertx.version} 137 | 138 | 139 | io.vertx 140 | vertx-docgen-processor 141 | processor 142 | 0.9.8 143 | 144 | 145 | 146 | -Acodegen.output=${project.basedir}/src/main 147 | -Adocgen.source=${docs.dir}/*.md 148 | -Adocgen.output=${project.basedir}/jekyll/guide/$lang 149 | -Adocgen.syntax=markdown 150 | -Amaven.groupId=${project.groupId} 151 | -Amaven.artifactId=${project.artifactId} 152 | -Amaven.version=${project.version} 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | maven-javadoc-plugin 164 | ${maven.javadoc.plugin.version} 165 | 166 | ${project.build.sourceDirectory};${project.build.directory}/generated-sources/annotations 167 | 168 | com/julienviet/**/*.java 169 | 170 | 171 | **/package-info.java 172 | **/impl/** 173 | 174 | 175 | 176 | 177 | http://vertx.io/docs/apidocs/ 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | site-gen 188 | 189 | 190 | !skipSite 191 | 192 | 193 | 194 | 195 | rubygems-releases 196 | http://rubygems-proxy.torquebox.org/releases 197 | 198 | 199 | 200 | 201 | rubygems-releases 202 | http://rubygems-proxy.torquebox.org/releases 203 | 204 | 205 | 206 | 207 | 208 | org.apache.maven.plugins 209 | maven-site-plugin 210 | 3.4 211 | 212 | true 213 | true 214 | 215 | 216 | 217 | maven-javadoc-plugin 218 | 219 | 220 | site 221 | 222 | false 223 | ${project.basedir}/jekyll 224 | 225 | 226 | javadoc 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /src/main/asciidoc/dataobjects.adoc: -------------------------------------------------------------------------------- 1 | = Cheatsheets 2 | 3 | [[ProcessOptions]] 4 | == ProcessOptions 5 | 6 | ++++ 7 | Options for spawning new processes. 8 | ++++ 9 | ''' 10 | 11 | [cols=">25%,25%,50%"] 12 | [frame="topbot"] 13 | |=== 14 | ^|Name | Type ^| Description 15 | |[[cwd]]`@cwd`|`String`|+++ 16 | Set the child process current working directory. 17 | +++ 18 | |[[env]]`@env`|`String`|+++ 19 | Set the child process environment variables as key-value pairs. 20 | +++ 21 | |=== 22 | 23 | -------------------------------------------------------------------------------- /src/main/docs/index.md: -------------------------------------------------------------------------------- 1 | # Child Process extension for Vert.x 2 | 3 | Child Process is a Vert.x component for spawning OS child processes. 4 | 5 | * based on https://github.com/brettwooldridge/NuProcess _Low-overhead, non-blocking I/O, external Process implementation for Java_. 6 | * standard streams are fully non blocking 7 | * spawned process can be killed 8 | 9 | ## Using Child Process 10 | 11 | To use Child Process, add the following dependency to the _dependencies_ section of your build descriptor: 12 | 13 | * Maven (in your `pom.xml`): 14 | 15 | ```xml 16 | 17 | ${maven.groupId} 18 | ${maven.artifactId} 19 | ${maven.version} 20 | 21 | ``` 22 | 23 | * Gradle (in your `build.gradle` file): 24 | 25 | ```$lang 26 | dependencies { 27 | compile '${maven.groupId}:${maven.artifactId}:${maven.version}' 28 | } 29 | ``` 30 | 31 | ## Spawning child processes 32 | 33 | You can spawn child processes with the {@link io.reactiverse.childprocess.Process#create} and {@link io.reactiverse.childprocess.ProcessBuilder#start} methods: 34 | 35 | ```$lang 36 | {@link examples.Examples#ex01} 37 | ``` 38 | 39 | the future returned by `start` completes when the process has started or failed 40 | 41 | you can give arguments to child processes 42 | 43 | ```$lang 44 | {@link examples.Examples#ex02} 45 | ``` 46 | 47 | by default child processes use the current process environment options, you can pass key-value pairs as new environment variables 48 | 49 | ```$lang 50 | {@link examples.Examples#ex03} 51 | ``` 52 | 53 | {@link io.reactiverse.childprocess.Process#env()} gives you the current process environment key-value pairs 54 | 55 | ```$lang 56 | {@link examples.Examples#ex04} 57 | ``` 58 | 59 | By default, the child processes uses the current process _current working directory_, the 60 | {@link io.reactiverse.childprocess.ProcessOptions#setCwd(java.lang.String)} option overrides it 61 | 62 | ```$lang 63 | {@link examples.Examples#ex05} 64 | ``` 65 | 66 | ## Interacting with child processes 67 | 68 | The child process streams are available as 69 | 70 | * {@link io.reactiverse.childprocess.Process#stdin()} 71 | * {@link io.reactiverse.childprocess.Process#stdout()} 72 | * {@link io.reactiverse.childprocess.Process#stderr()} 73 | 74 | ```$lang 75 | {@link examples.Examples#ex10} 76 | ``` 77 | 78 | Calling {@link io.reactiverse.childprocess.Process#kill()} kills the child process, on POSIX it sends the 79 | `SIGTERM` signal. 80 | 81 | ```$lang 82 | {@link examples.Examples#ex30} 83 | ``` 84 | 85 | Child processes can also be forcibly killed 86 | 87 | ```$lang 88 | {@link examples.Examples#ex31} 89 | ``` 90 | 91 | ## Child process lifecycle 92 | 93 | You can be aware of the child process termination 94 | 95 | ```$lang 96 | {@link examples.Examples#ex20} 97 | ``` 98 | -------------------------------------------------------------------------------- /src/main/generated/io/reactiverse/childprocess/ProcessOptionsConverter.java: -------------------------------------------------------------------------------- 1 | package io.reactiverse.childprocess; 2 | 3 | import io.vertx.core.json.JsonObject; 4 | import io.vertx.core.json.JsonArray; 5 | import java.time.Instant; 6 | import java.time.format.DateTimeFormatter; 7 | 8 | /** 9 | * Converter and mapper for {@link io.reactiverse.childprocess.ProcessOptions}. 10 | * NOTE: This class has been automatically generated from the {@link io.reactiverse.childprocess.ProcessOptions} original class using Vert.x codegen. 11 | */ 12 | public class ProcessOptionsConverter { 13 | 14 | static void fromJson(Iterable> json, ProcessOptions obj) { 15 | for (java.util.Map.Entry member : json) { 16 | switch (member.getKey()) { 17 | case "env": 18 | if (member.getValue() instanceof JsonObject) { 19 | java.util.Map map = new java.util.LinkedHashMap<>(); 20 | ((Iterable>)member.getValue()).forEach(entry -> { 21 | if (entry.getValue() instanceof String) 22 | map.put(entry.getKey(), (String)entry.getValue()); 23 | }); 24 | obj.setEnv(map); 25 | } 26 | break; 27 | case "cwd": 28 | if (member.getValue() instanceof String) { 29 | obj.setCwd((String)member.getValue()); 30 | } 31 | break; 32 | } 33 | } 34 | } 35 | 36 | static void toJson(ProcessOptions obj, JsonObject json) { 37 | toJson(obj, json.getMap()); 38 | } 39 | 40 | static void toJson(ProcessOptions obj, java.util.Map json) { 41 | if (obj.getEnv() != null) { 42 | JsonObject map = new JsonObject(); 43 | obj.getEnv().forEach((key, value) -> map.put(key, value)); 44 | json.put("env", map); 45 | } 46 | if (obj.getCwd() != null) { 47 | json.put("cwd", obj.getCwd()); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/examples/Examples.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package examples; 19 | 20 | import io.reactiverse.childprocess.Process; 21 | import io.reactiverse.childprocess.ProcessBuilder; 22 | import io.reactiverse.childprocess.ProcessOptions; 23 | import io.vertx.core.Future; 24 | import io.vertx.core.Vertx; 25 | import io.vertx.core.buffer.Buffer; 26 | import io.vertx.docgen.Source; 27 | 28 | import java.util.Arrays; 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | /** 33 | * @author Julien Viet 34 | */ 35 | @Source 36 | public class Examples { 37 | 38 | public void ex01(Vertx vertx) { 39 | // Create the process builder 40 | ProcessBuilder processBuilder = Process.create(vertx, "ls"); 41 | 42 | // Start the process 43 | Future fut = processBuilder.start(); 44 | } 45 | 46 | public void ex02(Vertx vertx) { 47 | Process.create(vertx, "ls", Arrays.asList("-lh", "/usr")).start(); 48 | } 49 | 50 | public void ex03(Vertx vertx) { 51 | Map env = new HashMap<>(); 52 | env.put("MY_VAR", "whatever"); 53 | Process.create(vertx, "ls", new ProcessOptions().setEnv(env)).start(); 54 | } 55 | 56 | public void ex04(Vertx vertx) { 57 | ProcessOptions options = new ProcessOptions().setEnv(Process.env()); 58 | Process.create(vertx, "ls", options).start(); 59 | } 60 | 61 | public void ex05(Vertx vertx) { 62 | ProcessOptions options = new ProcessOptions().setCwd("/some-dir"); 63 | Process.create(vertx, "ls", options).start(); 64 | } 65 | 66 | public void ex10(Vertx vertx) { 67 | ProcessBuilder processBuilder = Process.create(vertx, "cat"); 68 | 69 | processBuilder.startHandler(process -> { 70 | process.stdout().handler(buff -> { 71 | System.out.println(buff.toString()); 72 | }); 73 | 74 | process.stdin().write(Buffer.buffer("Hello World")); 75 | }); 76 | 77 | processBuilder.start(); 78 | } 79 | 80 | public void ex20(Vertx vertx) { 81 | Process 82 | .create(vertx, "sleep", Arrays.asList("2")) 83 | .startHandler(process -> { 84 | process.exitHandler(code -> { 85 | System.out.println("Child process exited with code: " + code); 86 | }); 87 | }) 88 | .start(); 89 | } 90 | 91 | public void ex30(Vertx vertx) { 92 | Process 93 | .create(vertx, "cat") 94 | .startHandler(process -> { 95 | 96 | process.stdout().handler(buff -> { 97 | System.out.println(buff.toString()); 98 | }); 99 | 100 | process.stdin().write(Buffer.buffer("Hello World")); 101 | 102 | // Kill the process 103 | process.kill(); 104 | }) 105 | .start(); 106 | } 107 | 108 | public void ex31(Vertx vertx) { 109 | Process 110 | .create(vertx, "cat") 111 | .startHandler(process -> { 112 | 113 | process.stdout().handler(buff -> { 114 | System.out.println(buff.toString()); 115 | }); 116 | 117 | process.stdin().write(Buffer.buffer("Hello World")); 118 | 119 | // Kill the process forcibly 120 | process.kill(true); 121 | 122 | }).start(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/Process.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.reactiverse.childprocess; 19 | 20 | import io.reactiverse.childprocess.impl.ProcessBuilderImpl; 21 | import io.vertx.codegen.annotations.CacheReturn; 22 | import io.vertx.codegen.annotations.Fluent; 23 | import io.vertx.codegen.annotations.VertxGen; 24 | import io.vertx.core.Handler; 25 | import io.vertx.core.Vertx; 26 | import io.vertx.core.internal.ContextInternal; 27 | 28 | import java.util.Collections; 29 | import java.util.HashMap; 30 | import java.util.List; 31 | import java.util.Map; 32 | 33 | /** 34 | * A process launched from this current process. 35 | *

36 | * Please see the user manual for more detailed usage information. 37 | * 38 | * @author Julien Viet 39 | */ 40 | @VertxGen 41 | public interface Process { 42 | 43 | /** 44 | * @return the current process environment variables 45 | */ 46 | static Map env() { 47 | return new HashMap<>(System.getenv()); 48 | } 49 | 50 | /** 51 | * Create a child process (not running) from this process, call {@link ProcessBuilder#start()} to start the process. 52 | * 53 | * @param vertx the vertx instance 54 | * @param command the command to run 55 | * @return the created child process 56 | */ 57 | static ProcessBuilder create(Vertx vertx, String command) { 58 | return create(vertx, command, Collections.emptyList(), new ProcessOptions()); 59 | } 60 | 61 | /** 62 | * Create a child process (not running) from this process, call {@link ProcessBuilder#start()} to start the process. 63 | * 64 | * @param vertx the vertx instance 65 | * @param command the command to run 66 | * @param args list of string arguments 67 | * @return the created child process 68 | */ 69 | static ProcessBuilder create(Vertx vertx, String command, List args) { 70 | return create(vertx, command, args, new ProcessOptions()); 71 | } 72 | 73 | /** 74 | * Create a child process (not running) from this process, call {@link ProcessBuilder#start()} to start the process. 75 | * 76 | * @param vertx the vertx instance 77 | * @param command the command to run 78 | * @param options the options to run the command 79 | * @return the created child process 80 | */ 81 | static ProcessBuilder create(Vertx vertx, String command, ProcessOptions options) { 82 | return create(vertx, command, Collections.emptyList(), options); 83 | } 84 | 85 | /** 86 | * Create a child process (not running) from this process, call {@link ProcessBuilder#start()} to start the process. 87 | * 88 | * @param vertx the vertx instance 89 | * @param command the command to run 90 | * @param args list of string arguments 91 | * @param options the options to run the command 92 | * @return the created child process 93 | */ 94 | static ProcessBuilder create(Vertx vertx, String command, List args, ProcessOptions options) { 95 | return new ProcessBuilderImpl((ContextInternal) vertx.getOrCreateContext(), command, args, options); 96 | } 97 | 98 | /** 99 | * Set the handler to be called when the process exits, the handler will be called with the 100 | * process status code value. 101 | * 102 | * @param handler the handler 103 | * @return a reference to this, so the API can be used fluently 104 | */ 105 | @Fluent 106 | Process exitHandler(Handler handler); 107 | 108 | /** 109 | * @return the process PID or null if the process is not running 110 | */ 111 | Integer pid(); 112 | 113 | /** 114 | * @return the process stdin stream 115 | */ 116 | @CacheReturn 117 | StreamOutput stdin(); 118 | 119 | /** 120 | * @return the process stdout stream 121 | */ 122 | @CacheReturn 123 | StreamInput stdout(); 124 | 125 | /** 126 | * @return the process stderr stream 127 | */ 128 | @CacheReturn 129 | StreamInput stderr(); 130 | 131 | /** 132 | * Terminates the process in a graceful manner. 133 | *

134 | * On a POSIX OS, it sends the {@code SIGTERM}. 135 | */ 136 | default void kill() { 137 | kill(false); 138 | } 139 | 140 | 141 | /** 142 | * Terminates the process. 143 | *

144 | * If {@code force} is {@code false}, the process will be terminated gracefully (i.e. its shutdown logic will 145 | * be allowed to execute), assuming the OS supports such behavior. Note that the process may not actually 146 | * terminate, as its cleanup logic may fail or it may choose to ignore the termination request. If a guarantee 147 | * of termination is required, call this method with force equal to true instead. 148 | *

149 | * If {@code force} is {@code true}, the process is guaranteed to terminate, but whether it is terminated 150 | * gracefully or not is OS-dependent. Note that it may take the OS a moment to terminate the process, so 151 | * {@link #isRunning()} may return {@code true} for a brief period after calling this method. 152 | *

153 | * On a POSIX OS, it sends the {@code SIGTERM} or {@code SIGKILL} signals. 154 | * 155 | * @param force if true is passed, the process will be forcibly killed 156 | */ 157 | void kill(boolean force); 158 | 159 | /** 160 | * Tests whether or not the process is still running or has exited. 161 | */ 162 | boolean isRunning(); 163 | 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/ProcessBuilder.java: -------------------------------------------------------------------------------- 1 | package io.reactiverse.childprocess; 2 | 3 | import io.vertx.codegen.annotations.Fluent; 4 | import io.vertx.codegen.annotations.VertxGen; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.Handler; 7 | 8 | @VertxGen 9 | public interface ProcessBuilder { 10 | 11 | /** 12 | * Start the process. 13 | */ 14 | Future start(); 15 | 16 | /** 17 | * Set the handler to be called when the process starts. 18 | * 19 | * @param handler the handler 20 | * @return a reference to this, so the API can be used fluently 21 | */ 22 | @Fluent 23 | ProcessBuilder startHandler(Handler handler); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/ProcessOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.reactiverse.childprocess; 19 | 20 | import io.vertx.codegen.annotations.DataObject; 21 | import io.vertx.codegen.json.annotations.JsonGen; 22 | import io.vertx.core.json.JsonObject; 23 | 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | /** 28 | * Options for spawning new processes. 29 | * 30 | * @author Julien Viet 31 | */ 32 | @DataObject 33 | @JsonGen(publicConverter = false) 34 | public class ProcessOptions { 35 | 36 | /** 37 | * The default environment variables = the current process environment variables 38 | */ 39 | public static final Map DEFAULT_ENV = System.getenv(); 40 | 41 | private Map env; 42 | private String cwd; 43 | 44 | public ProcessOptions() { 45 | this.env = new HashMap<>(DEFAULT_ENV); 46 | } 47 | 48 | public ProcessOptions(ProcessOptions that) { 49 | env = that.env != null ? new HashMap<>(that.env) : null; 50 | cwd = that.cwd; 51 | } 52 | 53 | public ProcessOptions(JsonObject json) { 54 | ProcessOptionsConverter.fromJson(json, this); 55 | } 56 | 57 | /** 58 | * @return the current options environment variables as key-value pairs 59 | */ 60 | public Map getEnv() { 61 | return env; 62 | } 63 | 64 | /** 65 | * Set the child process environment variables as key-value pairs. 66 | * 67 | * @param env the env variables 68 | * @return a reference to this, so the API can be used fluently 69 | */ 70 | public ProcessOptions setEnv(Map env) { 71 | this.env = env; 72 | return this; 73 | } 74 | 75 | /** 76 | * @return the child process current working directory 77 | */ 78 | public String getCwd() { 79 | return cwd; 80 | } 81 | 82 | /** 83 | * Set the child process current working directory. 84 | * 85 | * @param cwd the current working directory 86 | * @return a reference to this, so the API can be used fluently 87 | */ 88 | public ProcessOptions setCwd(String cwd) { 89 | this.cwd = cwd; 90 | return this; 91 | } 92 | 93 | public JsonObject toJson() { 94 | JsonObject json = new JsonObject(); 95 | ProcessOptionsConverter.toJson(this, json); 96 | return json; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/StartException.java: -------------------------------------------------------------------------------- 1 | package io.reactiverse.childprocess; 2 | 3 | import io.vertx.core.buffer.Buffer; 4 | 5 | public class StartException extends Exception { 6 | 7 | final int exitCode; 8 | final Buffer stdout; 9 | final Buffer stdin; 10 | 11 | public StartException(int exitCode, Buffer stdout, Buffer stdin) { 12 | this.exitCode = exitCode; 13 | this.stdout = stdout; 14 | this.stdin = stdin; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/StreamInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.reactiverse.childprocess; 19 | 20 | import io.vertx.codegen.annotations.Fluent; 21 | import io.vertx.codegen.annotations.VertxGen; 22 | import io.vertx.core.Handler; 23 | import io.vertx.core.buffer.Buffer; 24 | import io.vertx.core.streams.StreamBase; 25 | 26 | /** 27 | * The input of a process: a stream of {@link Buffer buffers}. 28 | * 29 | * @author Julien Viet 30 | */ 31 | @VertxGen 32 | public interface StreamInput extends StreamBase { 33 | 34 | /** 35 | * Set an exception handler on the read stream. 36 | * 37 | * @param handler the exception handler 38 | * @return a reference to this, so the API can be used fluently 39 | */ 40 | @Fluent 41 | StreamInput exceptionHandler(Handler handler); 42 | 43 | /** 44 | * Set a buffer handler. As bytes are read, the handler will be called with the data. 45 | * 46 | * @return a reference to this, so the API can be used fluently 47 | */ 48 | @Fluent 49 | StreamInput handler(Handler handler); 50 | 51 | /** 52 | * Set an end handler. Once the stream has ended, and there is no more data to be read, this handler will be called. 53 | * 54 | * @return a reference to this, so the API can be used fluently 55 | */ 56 | @Fluent 57 | StreamInput endHandler(Handler handler); 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/StreamOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.reactiverse.childprocess; 19 | 20 | import io.vertx.codegen.annotations.VertxGen; 21 | import io.vertx.core.Future; 22 | import io.vertx.core.Handler; 23 | import io.vertx.core.buffer.Buffer; 24 | import io.vertx.core.streams.WriteStream; 25 | 26 | /** 27 | * The output of a process: a stream of {@link Buffer buffers}. 28 | * 29 | * @author Julien Viet 30 | */ 31 | @VertxGen 32 | public interface StreamOutput extends WriteStream { 33 | 34 | @Override 35 | StreamOutput exceptionHandler(Handler handler); 36 | 37 | @Override 38 | Future write(Buffer buffer); 39 | 40 | @Override 41 | StreamOutput setWriteQueueMaxSize(int i); 42 | 43 | @Override 44 | StreamOutput drainHandler(Handler handler); 45 | 46 | /** 47 | * Calls {code close()}. 48 | */ 49 | @Override 50 | default Future end() { 51 | return close().mapEmpty(); 52 | } 53 | 54 | /** 55 | * Close the stream. 56 | */ 57 | Future close(); 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/impl/ProcessBuilderImpl.java: -------------------------------------------------------------------------------- 1 | package io.reactiverse.childprocess.impl; 2 | 3 | import io.reactiverse.childprocess.Process; 4 | import io.reactiverse.childprocess.ProcessBuilder; 5 | import io.reactiverse.childprocess.ProcessOptions; 6 | import io.reactiverse.childprocess.StartException; 7 | import com.zaxxer.nuprocess.NuProcess; 8 | import com.zaxxer.nuprocess.NuProcessBuilder; 9 | import com.zaxxer.nuprocess.NuProcessHandler; 10 | import io.vertx.core.Future; 11 | import io.vertx.core.Handler; 12 | import io.vertx.core.Promise; 13 | import io.vertx.core.buffer.Buffer; 14 | import io.vertx.core.internal.ContextInternal; 15 | 16 | import java.io.File; 17 | import java.nio.ByteBuffer; 18 | import java.util.ArrayList; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | public class ProcessBuilderImpl implements ProcessBuilder { 24 | 25 | private final ContextInternal context; 26 | private final String command; 27 | private final List args; 28 | private final ProcessOptions options; 29 | private Handler processHandler; 30 | 31 | public ProcessBuilderImpl(ContextInternal context, String command, List args, ProcessOptions options) { 32 | this.context = context; 33 | this.command = command; 34 | this.args = args; 35 | this.options = options; 36 | } 37 | 38 | @Override 39 | public Future start() { 40 | Promise promise = context.promise(); 41 | Map env = new HashMap<>(); 42 | if (options.getEnv() != null) { 43 | options.getEnv().entrySet().forEach(entry -> { 44 | if (entry.getValue() != null) { 45 | env.put(entry.getKey(), entry.getValue()); 46 | } 47 | }); 48 | } 49 | ArrayList commands = new ArrayList<>(); 50 | commands.add(command); 51 | commands.addAll(args); 52 | NuProcessBuilder builder = new NuProcessBuilder(commands, env); 53 | if (options.getCwd() != null) { 54 | builder.setCwd(new File(options.getCwd()).toPath()); 55 | } 56 | Buffer bufferedStdout = Buffer.buffer(); 57 | Buffer bufferedStderr = Buffer.buffer(); 58 | Handler handler = processHandler; // Capture 59 | builder.setProcessListener(new NuProcessHandler() { 60 | volatile ProcessImpl process; 61 | @Override 62 | public void onPreStart(NuProcess nuProcess) { 63 | } 64 | @Override 65 | public void onStart(NuProcess nuProcess) { 66 | ProcessImpl p = new ProcessImpl(context, nuProcess); 67 | process = p; 68 | if (handler != null) { 69 | context.emit(p, handler); 70 | } 71 | promise.complete(); 72 | } 73 | @Override 74 | public void onExit(int exitCode) { 75 | ProcessImpl p = process; 76 | if (p == null) { 77 | promise.fail(new StartException(exitCode, bufferedStdout, bufferedStderr)); 78 | } else { 79 | p.onExit(exitCode); 80 | } 81 | } 82 | private byte[] getBytes(ByteBuffer byteBuffer) { 83 | if (byteBuffer != null && byteBuffer.remaining() > 0) { 84 | byte[] bytes = new byte[byteBuffer.remaining()]; 85 | byteBuffer.get(bytes); 86 | return bytes; 87 | } else { 88 | return null; 89 | } 90 | } 91 | @Override 92 | public void onStdout(ByteBuffer byteBuffer, boolean closed) { 93 | byte[] bytes = getBytes(byteBuffer); 94 | ProcessImpl p = process; 95 | if (process != null) { 96 | p.onStdout(bytes != null ? Buffer.buffer(bytes) : null, closed); 97 | } else { 98 | if (bytes != null) { 99 | bufferedStdout.appendBytes(bytes); 100 | } 101 | } 102 | } 103 | @Override 104 | public void onStderr(ByteBuffer byteBuffer, boolean closed) { 105 | byte[] bytes = getBytes(byteBuffer); 106 | ProcessImpl p = process; 107 | if (p != null) { 108 | p.onStderr(bytes != null ? Buffer.buffer(bytes) : null, closed); 109 | } else { 110 | if (bytes != null) { 111 | bufferedStdout.appendBytes(bytes); 112 | } 113 | } 114 | } 115 | @Override 116 | public boolean onStdinReady(ByteBuffer buffer) { 117 | ProcessImpl p = process; 118 | return p.onStdinReady(buffer); 119 | } 120 | }); 121 | builder.start(); 122 | return promise.future(); 123 | } 124 | 125 | @Override 126 | public synchronized ProcessBuilder startHandler(Handler handler) { 127 | processHandler = handler; 128 | return this; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/impl/ProcessImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.reactiverse.childprocess.impl; 19 | 20 | import io.reactiverse.childprocess.StreamInput; 21 | import io.reactiverse.childprocess.StreamOutput; 22 | import com.zaxxer.nuprocess.NuProcess; 23 | import io.vertx.core.*; 24 | import io.vertx.core.buffer.Buffer; 25 | import io.reactiverse.childprocess.Process; 26 | import io.vertx.core.internal.ContextInternal; 27 | 28 | import java.nio.ByteBuffer; 29 | import java.util.ArrayDeque; 30 | 31 | /** 32 | * @author Julien Viet 33 | */ 34 | public class ProcessImpl implements Process, StreamOutput { 35 | 36 | private static final int OPEN = 0, CLOSING = 1, CLOSED = 2; 37 | 38 | private int stdinStatus = OPEN; 39 | private Promise stdninEnd; 40 | private final ArrayDeque stdinPending = new ArrayDeque<>(); 41 | private int stdinPendingSize; 42 | private int stdinMaxSize = 1024; 43 | private Handler drainHandler; 44 | private final ContextInternal context; 45 | private final ProcessStreamInput stdout; 46 | private final ProcessStreamInput stderr; 47 | private Handler exitHandler; 48 | private final NuProcess process; 49 | private Promise exitFuture; 50 | private boolean wantWrite; 51 | 52 | public ProcessImpl(ContextInternal context, NuProcess process) { 53 | this.context = context; 54 | this.process = process; 55 | this.stdout = new ProcessStreamInput(context); 56 | this.stderr = new ProcessStreamInput(context); 57 | this.exitFuture = context.promise(); 58 | this.stdninEnd = context.promise(); 59 | } 60 | 61 | // 62 | 63 | @Override 64 | public synchronized Process exitHandler(Handler handler) { 65 | exitHandler = handler; 66 | return this; 67 | } 68 | 69 | @Override 70 | public synchronized Integer pid() { 71 | return process.getPID(); 72 | } 73 | 74 | @Override 75 | public StreamOutput stdin() { 76 | return this; 77 | } 78 | 79 | @Override 80 | public StreamInput stdout() { 81 | return stdout; 82 | } 83 | 84 | @Override 85 | public StreamInput stderr() { 86 | return stderr; 87 | } 88 | 89 | // 90 | 91 | @Override 92 | public StreamOutput exceptionHandler(Handler handler) { 93 | return this; 94 | } 95 | 96 | @Override 97 | public Future write(Buffer buffer) { 98 | Promise promise = context.promise(); 99 | synchronized (this) { 100 | if (stdinStatus == CLOSING || stdinStatus == CLOSED) { 101 | throw new IllegalStateException(); 102 | } 103 | stdinPending.add(new Write(buffer, promise)); 104 | stdinPendingSize += buffer.length(); 105 | if (process != null && !wantWrite) { 106 | wantWrite = true; 107 | process.wantWrite(); 108 | } 109 | } 110 | return promise.future(); 111 | } 112 | 113 | @Override 114 | public synchronized StreamOutput setWriteQueueMaxSize(int i) { 115 | stdinMaxSize = i; 116 | return this; 117 | } 118 | 119 | @Override 120 | public StreamOutput drainHandler(Handler handler) { 121 | synchronized (this) { 122 | drainHandler = handler; 123 | } 124 | checkDrained(); 125 | return this; 126 | } 127 | 128 | @Override 129 | public synchronized boolean writeQueueFull() { 130 | return stdinPendingSize > stdinMaxSize; 131 | } 132 | 133 | @Override 134 | public Future close() { 135 | synchronized (this) { 136 | if (stdinStatus != OPEN) { 137 | return stdninEnd.future(); 138 | } 139 | if (stdinPendingSize == 0) { 140 | stdinStatus = CLOSED; 141 | } else { 142 | stdinStatus = CLOSING; 143 | return stdninEnd.future(); 144 | } 145 | } 146 | process.closeStdin(false); 147 | stdninEnd.complete(); 148 | return stdninEnd.future(); 149 | } 150 | 151 | // 152 | 153 | public synchronized void onExit(int exitCode) { 154 | synchronized (this) { 155 | stdinStatus = CLOSED; 156 | } 157 | handleExit(exitCode); 158 | } 159 | 160 | private void handleExit(int exitCode) { 161 | exitFuture.complete(exitCode); 162 | Handler handler = exitHandler; 163 | if (handler != null) { 164 | context.emit(exitCode, handler); 165 | } 166 | } 167 | 168 | public void onStdout(Buffer buffer, boolean closed) { 169 | if (buffer != null) { 170 | stdout.write(buffer); 171 | } 172 | if (closed) { 173 | stdout.close(); 174 | } 175 | } 176 | 177 | public void onStderr(Buffer buffer, boolean closed) { 178 | if (buffer != null) { 179 | stderr.write(buffer); 180 | } 181 | if (closed) { 182 | stderr.close(); 183 | } 184 | } 185 | 186 | public boolean onStdinReady(ByteBuffer byteBuffer) { 187 | synchronized (this) { 188 | Write write; 189 | while (byteBuffer.remaining() > 0 && (write = stdinPending.poll()) != null) { 190 | byte[] bytes; 191 | if (write.buffer.length() <= byteBuffer.remaining()) { 192 | bytes = write.buffer.getBytes(); 193 | write.promise.complete(); 194 | } else { 195 | bytes = write.buffer.getBytes(0, byteBuffer.remaining()); 196 | stdinPending.addFirst(new Write(write.buffer.slice(byteBuffer.remaining(), write.buffer.length()), write.promise)); 197 | } 198 | byteBuffer.put(bytes); // See to do directly with Netty ByteBuf 199 | stdinPendingSize -= bytes.length; 200 | } 201 | byteBuffer.flip(); 202 | context.execute(v -> checkDrained()); 203 | if (stdinPendingSize > 0) { 204 | return true; 205 | } else { 206 | wantWrite = false; 207 | if (stdinStatus == CLOSING) { 208 | stdinStatus = CLOSED; 209 | } else { 210 | return false; 211 | } 212 | } 213 | } 214 | process.closeStdin(false); 215 | stdninEnd.complete(); 216 | return false; 217 | } 218 | 219 | private void checkDrained() { 220 | Handler handler; 221 | synchronized (this) { 222 | if (stdinPendingSize >= stdinMaxSize / 2) { 223 | return; 224 | } 225 | handler = drainHandler; 226 | drainHandler = null; 227 | } 228 | if (handler != null) { 229 | context.emit(handler); 230 | } 231 | } 232 | 233 | @Override 234 | public void kill(boolean force) { 235 | if (process != null) { 236 | process.destroy(force); 237 | } 238 | } 239 | 240 | @Override 241 | public boolean isRunning() { 242 | return process.isRunning(); 243 | } 244 | 245 | private static class Write { 246 | final Buffer buffer; 247 | final Promise promise; 248 | Write(Buffer buffer, Promise promise) { 249 | this.buffer = buffer; 250 | this.promise = promise; 251 | } 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/impl/ProcessStreamInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.reactiverse.childprocess.impl; 19 | 20 | import io.vertx.core.Handler; 21 | import io.vertx.core.buffer.Buffer; 22 | import io.reactiverse.childprocess.StreamInput; 23 | import io.vertx.core.internal.ContextInternal; 24 | 25 | /** 26 | * @author Julien Viet 27 | */ 28 | public class ProcessStreamInput implements StreamInput { 29 | 30 | private final ContextInternal context; 31 | private Handler dataHandler; 32 | private Handler endHandler; 33 | 34 | ProcessStreamInput(ContextInternal context) { 35 | this.context = context; 36 | } 37 | 38 | synchronized void write(Buffer buffer) { 39 | sendBuffer(buffer); 40 | } 41 | 42 | void close() { 43 | Handler handler = endHandler; 44 | if (handler != null) { 45 | context.emit(handler); 46 | } 47 | } 48 | 49 | private void sendBuffer(Buffer buffer) { 50 | Handler handler = dataHandler; 51 | if (handler != null) { 52 | context.emit(buffer, handler); 53 | } 54 | } 55 | 56 | @Override 57 | public StreamInput exceptionHandler(Handler handler) { 58 | return this; 59 | } 60 | 61 | @Override 62 | public StreamInput handler(Handler handler) { 63 | this.dataHandler = handler; 64 | return this; 65 | } 66 | 67 | @Override 68 | public StreamInput endHandler(Handler handler) { 69 | this.endHandler = handler; 70 | return this; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/childprocess/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | @ModuleGen(name = "childprocess", groupPackage = "io.reactiverse") 19 | package io.reactiverse.childprocess; 20 | 21 | import io.vertx.codegen.annotations.ModuleGen; 22 | -------------------------------------------------------------------------------- /src/test/java/EchoStderr.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /** 19 | * @author Julien Viet 20 | */ 21 | public class EchoStderr { 22 | 23 | public static void main(String[] args) { 24 | for (String arg : args) { 25 | System.err.print(arg); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/EchoStdout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /** 19 | * @author Julien Viet 20 | */ 21 | public class EchoStdout { 22 | 23 | public static void main(String[] args) { 24 | for (String arg : args) { 25 | System.out.print(arg); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/ExitCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /** 19 | * @author Julien Viet 20 | */ 21 | public class ExitCode { 22 | 23 | public static void main(String[] args) { 24 | System.exit(25); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/PrintCwd.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import java.io.File; 19 | 20 | /** 21 | * @author Julien Viet 22 | */ 23 | public class PrintCwd { 24 | 25 | public static void main(String[] args) { 26 | System.out.print(new File("").getAbsolutePath()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/PrintEnv.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /** 19 | * @author Julien Viet 20 | */ 21 | public class PrintEnv { 22 | 23 | public static void main(String[] args) { 24 | String val = System.getenv(args[0]); 25 | if (val != null) { 26 | System.out.print(val); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/Shutdown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /** 19 | * @author Julien Viet 20 | */ 21 | public class Shutdown { 22 | 23 | public static void main(String[] args) throws Exception { 24 | Runtime.getRuntime().addShutdownHook(new Thread() { 25 | @Override 26 | public void run() { 27 | System.out.print("exited"); 28 | } 29 | }); 30 | System.out.print("ok"); 31 | Thread.sleep(10000); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/StdoutLongSequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /** 19 | * @author Julien Viet 20 | */ 21 | public class StdoutLongSequence { 22 | 23 | public static void main(String[] args) { 24 | for (int i = 0;i < 100000;i++) { 25 | System.out.print("" + i); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/io/reactiverse/childprocess/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Julien Viet 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package io.reactiverse.childprocess; 19 | 20 | import java.io.File; 21 | 22 | /** 23 | * @author Julien Viet 24 | */ 25 | public class Main { 26 | 27 | public static void main(String[] args) throws Exception { 28 | 29 | File f = new File(args[0]); 30 | if (!f.exists()) { 31 | System.exit(-1); 32 | } 33 | 34 | while (f.length() == 0) { 35 | Thread.sleep(1); 36 | } 37 | 38 | while (true) { 39 | int c = System.in.read(); 40 | if (c == 'h' || c == 'e' || c == 'l' || c == 'o') { 41 | int a = 0; 42 | } else { 43 | if (c == -1) { 44 | System.exit(-1); 45 | } else if (c == 4) { 46 | break; 47 | } 48 | } 49 | } 50 | 51 | } 52 | } 53 | --------------------------------------------------------------------------------