warbler 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/{History.txt → CHANGELOG.md} +55 -45
- data/Gemfile +5 -7
- data/LICENSE.txt +4 -6
- data/Mavenfile +16 -23
- data/README.rdoc +62 -13
- data/Rakefile +1 -3
- data/ext/JarMain.java +99 -98
- data/ext/WarMain.java +47 -66
- data/lib/warbler/bundler_helper.rb +1 -8
- data/lib/warbler/config.rb +7 -9
- data/lib/warbler/gems.rb +3 -7
- data/lib/warbler/jar.rb +2 -11
- data/lib/warbler/task.rb +8 -5
- data/lib/warbler/traits/gemspec.rb +4 -0
- data/lib/warbler/traits/jar.rb +5 -1
- data/lib/warbler/traits/jbundler.rb +2 -1
- data/lib/warbler/traits/nogemspec.rb +5 -1
- data/lib/warbler/traits/rack.rb +5 -1
- data/lib/warbler/traits/rails.rb +4 -0
- data/lib/warbler/traits/war.rb +4 -0
- data/lib/warbler/traits.rb +29 -5
- data/lib/warbler/version.rb +1 -1
- data/lib/warbler/web_server.rb +3 -1
- data/lib/warbler_jar.jar +0 -0
- data/warble.rb +22 -5
- data/warbler.gemspec +10 -4
- data/web.xml.erb +0 -19
- metadata +73 -20
- data/lib/warbler/war.rb +0 -8
data/ext/JarMain.java
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
* See the file LICENSE.txt for details.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import java.io.Closeable;
|
|
8
9
|
import java.io.File;
|
|
9
|
-
import java.io.IOException;
|
|
10
10
|
import java.io.FileOutputStream;
|
|
11
|
+
import java.io.IOException;
|
|
11
12
|
import java.io.InputStream;
|
|
13
|
+
import java.io.OutputStream;
|
|
12
14
|
import java.io.PrintStream;
|
|
13
15
|
import java.lang.reflect.InvocationTargetException;
|
|
14
16
|
import java.lang.reflect.Method;
|
|
@@ -18,14 +20,18 @@ import java.net.URL;
|
|
|
18
20
|
import java.net.URLClassLoader;
|
|
19
21
|
import java.util.ArrayList;
|
|
20
22
|
import java.util.Arrays;
|
|
23
|
+
import java.util.Deque;
|
|
21
24
|
import java.util.Enumeration;
|
|
22
25
|
import java.util.HashMap;
|
|
23
26
|
import java.util.List;
|
|
24
27
|
import java.util.Map;
|
|
28
|
+
import java.util.Objects;
|
|
29
|
+
import java.util.concurrent.Callable;
|
|
30
|
+
import java.util.concurrent.ConcurrentLinkedDeque;
|
|
25
31
|
import java.util.jar.JarEntry;
|
|
26
32
|
import java.util.jar.JarFile;
|
|
27
33
|
|
|
28
|
-
public class JarMain implements
|
|
34
|
+
public class JarMain implements Closeable {
|
|
29
35
|
|
|
30
36
|
static final String MAIN = '/' + JarMain.class.getName().replace('.', '/') + ".class";
|
|
31
37
|
|
|
@@ -34,66 +40,61 @@ public class JarMain implements Runnable {
|
|
|
34
40
|
private final String path;
|
|
35
41
|
|
|
36
42
|
protected File extractRoot;
|
|
37
|
-
|
|
38
|
-
protected URLClassLoader classLoader;
|
|
43
|
+
final Deque<Closeable> closeables = new ConcurrentLinkedDeque<>();
|
|
39
44
|
|
|
40
45
|
JarMain(String[] args) {
|
|
41
46
|
this.args = args;
|
|
42
|
-
URL mainClass = getClass().getResource(MAIN);
|
|
47
|
+
URL mainClass = Objects.requireNonNull(getClass().getResource(MAIN), MAIN + " not found!");
|
|
43
48
|
URI uri;
|
|
44
|
-
File file;
|
|
45
49
|
String pathWithoutMain;
|
|
46
50
|
|
|
47
51
|
try {
|
|
48
52
|
this.path = mainClass.toURI().getSchemeSpecificPart();
|
|
49
53
|
pathWithoutMain = mainClass.toURI().getRawSchemeSpecificPart().replace("!" + MAIN, "");
|
|
50
54
|
uri = new URI(pathWithoutMain);
|
|
51
|
-
}
|
|
52
|
-
catch (URISyntaxException e) {
|
|
55
|
+
} catch (URISyntaxException e) {
|
|
53
56
|
throw new RuntimeException(e);
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
archive = new File(uri.getPath()).getAbsolutePath();
|
|
57
60
|
|
|
58
|
-
Runtime.getRuntime().addShutdownHook(new Thread(this));
|
|
61
|
+
Runtime.getRuntime().addShutdownHook(new Thread(this::close, "Warbler-Shutdown"));
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
protected URL[] extractArchive() throws Exception {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
Map<String, JarEntry> jarNames = new HashMap<String, JarEntry>();
|
|
65
|
+
try (JarFile jarFile = new JarFile(archive)) {
|
|
66
|
+
Map<String, JarEntry> jarNames = new HashMap<>();
|
|
65
67
|
for (Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); ) {
|
|
66
68
|
JarEntry entry = e.nextElement();
|
|
67
69
|
String extractPath = getExtractEntryPath(entry);
|
|
68
|
-
if (
|
|
70
|
+
if (extractPath != null) jarNames.put(extractPath, entry);
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
extractRoot = File.createTempFile("jruby", "extract");
|
|
72
|
-
extractRoot.delete();
|
|
74
|
+
extractRoot.delete();
|
|
75
|
+
extractRoot.mkdirs();
|
|
76
|
+
closeables.add(() -> deleteAll(extractRoot));
|
|
73
77
|
|
|
74
|
-
final List<URL> urls = new ArrayList
|
|
78
|
+
final List<URL> urls = new ArrayList<>(jarNames.size());
|
|
75
79
|
for (Map.Entry<String, JarEntry> e : jarNames.entrySet()) {
|
|
76
80
|
URL entryURL = extractEntry(e.getValue(), e.getKey());
|
|
77
|
-
if (entryURL != null) urls.add(
|
|
81
|
+
if (entryURL != null) urls.add(entryURL);
|
|
78
82
|
}
|
|
79
|
-
return urls.toArray(new URL[
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
jarFile.close();
|
|
83
|
+
return urls.toArray(new URL[0]);
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
protected String getExtractEntryPath(final JarEntry entry) {
|
|
87
88
|
final String name = entry.getName();
|
|
88
|
-
if (
|
|
89
|
+
if (name.startsWith("META-INF/lib") && name.endsWith(".jar")) {
|
|
89
90
|
return name.substring(name.lastIndexOf('/') + 1);
|
|
90
91
|
}
|
|
91
92
|
return null; // do not extract entry
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
protected URL extractEntry(final JarEntry entry,
|
|
95
|
-
|
|
96
|
-
if (
|
|
95
|
+
protected URL extractEntry(final JarEntry entry, String path) throws Exception {
|
|
96
|
+
File file = new File(extractRoot, path);
|
|
97
|
+
if (entry.isDirectory()) {
|
|
97
98
|
file.mkdirs();
|
|
98
99
|
return null;
|
|
99
100
|
}
|
|
@@ -101,44 +102,34 @@ public class JarMain implements Runnable {
|
|
|
101
102
|
final InputStream entryStream;
|
|
102
103
|
try {
|
|
103
104
|
entryStream = new URI("jar", entryPath, null).toURL().openStream();
|
|
104
|
-
}
|
|
105
|
-
catch (IllegalArgumentException e) {
|
|
105
|
+
} catch (IllegalArgumentException e) {
|
|
106
106
|
// TODO gems '%' file name "encoding" ?!
|
|
107
107
|
debug("failed to open jar:" + entryPath + " skipping entry: " + entry.getName(), e);
|
|
108
108
|
return null;
|
|
109
109
|
}
|
|
110
110
|
final File parent = file.getParentFile();
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
int bytesRead;
|
|
116
|
-
while ((bytesRead = entryStream.read(buf)) != -1) {
|
|
117
|
-
outStream.write(buf, 0, bytesRead);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
entryStream.close();
|
|
122
|
-
outStream.close();
|
|
123
|
-
file.deleteOnExit();
|
|
124
|
-
}
|
|
111
|
+
if (parent != null) parent.mkdirs();
|
|
112
|
+
|
|
113
|
+
transferAndClose(() -> entryStream, () -> new FileOutputStream(file));
|
|
114
|
+
file.deleteOnExit();
|
|
125
115
|
// if (false) debug(entry.getName() + " extracted to " + file.getPath());
|
|
126
116
|
return file.toURI().toURL();
|
|
127
117
|
}
|
|
128
118
|
|
|
129
119
|
protected String entryPath(String name) {
|
|
130
|
-
if (
|
|
120
|
+
if (!name.startsWith("/")) name = "/" + name;
|
|
131
121
|
return path.replace(MAIN, name);
|
|
132
122
|
}
|
|
133
123
|
|
|
134
124
|
protected Object newScriptingContainer(final URL[] jars) throws Exception {
|
|
135
125
|
setSystemProperty("org.jruby.embed.class.path", "");
|
|
136
|
-
|
|
137
|
-
|
|
126
|
+
URLClassLoader scriptingClassLoader = new URLClassLoader(jars);
|
|
127
|
+
closeables.add(scriptingClassLoader);
|
|
128
|
+
Class<?> scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, scriptingClassLoader);
|
|
138
129
|
Object scriptingContainer = scriptingContainerClass.newInstance();
|
|
139
130
|
debug("scripting container class loader urls: " + Arrays.toString(jars));
|
|
140
131
|
invokeMethod(scriptingContainer, "setArgv", (Object) args);
|
|
141
|
-
invokeMethod(scriptingContainer, "setClassLoader", new Class[]
|
|
132
|
+
invokeMethod(scriptingContainer, "setClassLoader", new Class[]{ClassLoader.class}, scriptingClassLoader);
|
|
142
133
|
return scriptingContainer;
|
|
143
134
|
}
|
|
144
135
|
|
|
@@ -146,18 +137,18 @@ public class JarMain implements Runnable {
|
|
|
146
137
|
final Object scriptingContainer = newScriptingContainer(jars);
|
|
147
138
|
debug("invoking " + archive + " with: " + Arrays.deepToString(args));
|
|
148
139
|
Object outcome = invokeMethod(scriptingContainer, "runScriptlet", launchScript());
|
|
149
|
-
return (
|
|
140
|
+
return (outcome instanceof Number) ? ((Number) outcome).intValue() : 0;
|
|
150
141
|
}
|
|
151
142
|
|
|
152
143
|
protected String launchScript() {
|
|
153
144
|
return
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
145
|
+
"begin\n" +
|
|
146
|
+
" require 'META-INF/init.rb'\n" +
|
|
147
|
+
" require 'META-INF/main.rb'\n" +
|
|
148
|
+
" 0\n" +
|
|
149
|
+
"rescue SystemExit => e\n" +
|
|
150
|
+
" e.status\n" +
|
|
151
|
+
"end";
|
|
161
152
|
}
|
|
162
153
|
|
|
163
154
|
protected int start() throws Exception {
|
|
@@ -170,8 +161,8 @@ public class JarMain implements Runnable {
|
|
|
170
161
|
}
|
|
171
162
|
|
|
172
163
|
protected void debug(String msg, Throwable t) {
|
|
173
|
-
if (
|
|
174
|
-
if (
|
|
164
|
+
if (isDebug()) System.out.println(msg);
|
|
165
|
+
if (isDebug() && t != null) t.printStackTrace(System.out);
|
|
175
166
|
}
|
|
176
167
|
|
|
177
168
|
protected static void debug(Throwable t) {
|
|
@@ -179,7 +170,7 @@ public class JarMain implements Runnable {
|
|
|
179
170
|
}
|
|
180
171
|
|
|
181
172
|
private static void debug(Throwable t, PrintStream out) {
|
|
182
|
-
if (
|
|
173
|
+
if (isDebug()) t.printStackTrace(out);
|
|
183
174
|
}
|
|
184
175
|
|
|
185
176
|
protected void warn(String msg) {
|
|
@@ -195,39 +186,42 @@ public class JarMain implements Runnable {
|
|
|
195
186
|
debug(t, System.err);
|
|
196
187
|
}
|
|
197
188
|
|
|
198
|
-
protected void
|
|
189
|
+
protected void deleteAll(File f) {
|
|
199
190
|
try {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
191
|
+
if (f.isDirectory() && !isSymlink(f)) {
|
|
192
|
+
File[] children = f.listFiles();
|
|
193
|
+
if (children != null) {
|
|
194
|
+
for (File child : children) {
|
|
195
|
+
deleteAll(child);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
f.delete();
|
|
200
|
+
} catch (IOException e) {
|
|
201
|
+
error(e);
|
|
207
202
|
}
|
|
208
|
-
catch (IOException e) { error(e); }
|
|
209
203
|
}
|
|
210
204
|
|
|
211
205
|
protected boolean isSymlink(File file) throws IOException {
|
|
212
206
|
if (file == null) throw new NullPointerException("File must not be null");
|
|
213
207
|
final File canonical;
|
|
214
|
-
if (
|
|
208
|
+
if (file.getParent() == null) canonical = file;
|
|
215
209
|
else {
|
|
216
210
|
File parentDir = file.getParentFile().getCanonicalFile();
|
|
217
211
|
canonical = new File(parentDir, file.getName());
|
|
218
212
|
}
|
|
219
|
-
return !
|
|
213
|
+
return !canonical.getCanonicalFile().equals(canonical.getAbsoluteFile());
|
|
220
214
|
}
|
|
221
215
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
216
|
+
@Override
|
|
217
|
+
public void close() {
|
|
218
|
+
closeables.descendingIterator().forEachRemaining(closeableResource -> {
|
|
219
|
+
try {
|
|
220
|
+
closeableResource.close();
|
|
221
|
+
} catch (Exception e) {
|
|
222
|
+
error("Error during shutdown", e);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
231
225
|
}
|
|
232
226
|
|
|
233
227
|
public static void main(String[] args) {
|
|
@@ -238,38 +232,35 @@ public class JarMain implements Runnable {
|
|
|
238
232
|
int exit;
|
|
239
233
|
try {
|
|
240
234
|
exit = main.start();
|
|
241
|
-
}
|
|
242
|
-
catch (Exception e) {
|
|
235
|
+
} catch (Exception e) {
|
|
243
236
|
Throwable t = e;
|
|
244
|
-
while (
|
|
237
|
+
while (t.getCause() != null && t.getCause() != t) {
|
|
245
238
|
t = t.getCause();
|
|
246
239
|
}
|
|
247
240
|
error(e.toString(), t);
|
|
248
241
|
exit = 1;
|
|
249
242
|
}
|
|
250
243
|
try {
|
|
251
|
-
if (
|
|
252
|
-
}
|
|
253
|
-
catch (SecurityException e) {
|
|
244
|
+
if (isSystemExitEnabled()) System.exit(exit);
|
|
245
|
+
} catch (SecurityException e) {
|
|
254
246
|
debug(e);
|
|
255
247
|
}
|
|
256
248
|
}
|
|
257
249
|
|
|
258
250
|
protected static Object invokeMethod(final Object self, final String name, final Object... args)
|
|
259
|
-
throws
|
|
251
|
+
throws Exception {
|
|
260
252
|
|
|
261
|
-
final Class[] signature = new Class[args.length];
|
|
262
|
-
for (
|
|
253
|
+
final Class<?>[] signature = new Class[args.length];
|
|
254
|
+
for (int i = 0; i < args.length; i++) signature[i] = args[i].getClass();
|
|
263
255
|
return invokeMethod(self, name, signature, args);
|
|
264
256
|
}
|
|
265
257
|
|
|
266
|
-
protected static Object invokeMethod(final Object self, final String name, final Class[] signature, final Object... args)
|
|
267
|
-
throws
|
|
258
|
+
protected static Object invokeMethod(final Object self, final String name, final Class<?>[] signature, final Object... args)
|
|
259
|
+
throws Exception {
|
|
268
260
|
Method method = self.getClass().getDeclaredMethod(name, signature);
|
|
269
261
|
try {
|
|
270
262
|
return method.invoke(self, args);
|
|
271
|
-
}
|
|
272
|
-
catch (InvocationTargetException e) {
|
|
263
|
+
} catch (InvocationTargetException e) {
|
|
273
264
|
Throwable target = e.getTargetException();
|
|
274
265
|
if (target instanceof Exception) {
|
|
275
266
|
throw (Exception) target;
|
|
@@ -279,18 +270,21 @@ public class JarMain implements Runnable {
|
|
|
279
270
|
}
|
|
280
271
|
|
|
281
272
|
private static final boolean debug;
|
|
273
|
+
|
|
282
274
|
static {
|
|
283
|
-
debug = Boolean.parseBoolean(
|
|
275
|
+
debug = Boolean.parseBoolean(getSystemProperty("warbler.debug", "false"));
|
|
284
276
|
}
|
|
285
277
|
|
|
286
|
-
static boolean isDebug() {
|
|
278
|
+
static boolean isDebug() {
|
|
279
|
+
return debug;
|
|
280
|
+
}
|
|
287
281
|
|
|
288
282
|
/**
|
|
289
283
|
* if warbler.skip_system_exit system property is defined, we will not
|
|
290
284
|
* call System.exit in the normal flow. System.exit can cause problems
|
|
291
285
|
* for wrappers like procrun
|
|
292
286
|
*/
|
|
293
|
-
private static boolean isSystemExitEnabled(){
|
|
287
|
+
private static boolean isSystemExitEnabled() {
|
|
294
288
|
return getSystemProperty("warbler.skip_system_exit") == null; //omission enables System.exit use
|
|
295
289
|
}
|
|
296
290
|
|
|
@@ -301,8 +295,7 @@ public class JarMain implements Runnable {
|
|
|
301
295
|
static String getSystemProperty(final String name, final String defaultValue) {
|
|
302
296
|
try {
|
|
303
297
|
return System.getProperty(name, defaultValue);
|
|
304
|
-
}
|
|
305
|
-
catch (SecurityException e) {
|
|
298
|
+
} catch (SecurityException e) {
|
|
306
299
|
return defaultValue;
|
|
307
300
|
}
|
|
308
301
|
}
|
|
@@ -311,8 +304,7 @@ public class JarMain implements Runnable {
|
|
|
311
304
|
try {
|
|
312
305
|
System.setProperty(name, value);
|
|
313
306
|
return true;
|
|
314
|
-
}
|
|
315
|
-
catch (SecurityException e) {
|
|
307
|
+
} catch (SecurityException e) {
|
|
316
308
|
return false;
|
|
317
309
|
}
|
|
318
310
|
}
|
|
@@ -323,14 +315,23 @@ public class JarMain implements Runnable {
|
|
|
323
315
|
|
|
324
316
|
static String getENV(final String name, final String defaultValue) {
|
|
325
317
|
try {
|
|
326
|
-
if (
|
|
318
|
+
if (System.getenv().containsKey(name)) {
|
|
327
319
|
return System.getenv().get(name);
|
|
328
320
|
}
|
|
329
321
|
return defaultValue;
|
|
330
|
-
}
|
|
331
|
-
catch (SecurityException e) {
|
|
322
|
+
} catch (SecurityException e) {
|
|
332
323
|
return defaultValue;
|
|
333
324
|
}
|
|
334
325
|
}
|
|
335
326
|
|
|
327
|
+
// Can be replaced with InputStream.transferTo(OutputStream) in Java 11+
|
|
328
|
+
static void transferAndClose(Callable<InputStream> is, Callable<OutputStream> os) throws Exception {
|
|
329
|
+
try (InputStream input = is.call(); OutputStream output = os.call()) {
|
|
330
|
+
byte[] buf = new byte[16384];
|
|
331
|
+
int bytesRead;
|
|
332
|
+
while ((bytesRead = input.read(buf)) != -1) {
|
|
333
|
+
output.write(buf, 0, bytesRead);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
336
337
|
}
|
data/ext/WarMain.java
CHANGED
|
@@ -5,38 +5,39 @@
|
|
|
5
5
|
* See the file LICENSE.txt for details.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import java.lang.reflect.Method;
|
|
9
|
-
import java.io.InputStream;
|
|
10
8
|
import java.io.ByteArrayInputStream;
|
|
11
|
-
import java.io.SequenceInputStream;
|
|
12
9
|
import java.io.File;
|
|
13
10
|
import java.io.FileNotFoundException;
|
|
14
11
|
import java.io.FileOutputStream;
|
|
12
|
+
import java.io.IOException;
|
|
13
|
+
import java.io.InputStream;
|
|
14
|
+
import java.io.SequenceInputStream;
|
|
15
|
+
import java.lang.reflect.Method;
|
|
15
16
|
import java.net.URI;
|
|
16
|
-
import java.net.URLClassLoader;
|
|
17
17
|
import java.net.URL;
|
|
18
|
+
import java.net.URLClassLoader;
|
|
18
19
|
import java.util.Arrays;
|
|
19
20
|
import java.util.List;
|
|
20
|
-
import java.util.Properties;
|
|
21
21
|
import java.util.Map;
|
|
22
|
+
import java.util.Properties;
|
|
22
23
|
import java.util.jar.JarEntry;
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Used as a Main-Class in the manifest for a .war file, so that you can run
|
|
26
27
|
* a .war file with <tt>java -jar</tt>.
|
|
27
|
-
*
|
|
28
|
+
* <p/>
|
|
28
29
|
* WarMain can be used with different web server libraries. WarMain expects
|
|
29
30
|
* to have two files present in the .war file,
|
|
30
31
|
* <tt>WEB-INF/webserver.properties</tt> and <tt>WEB-INF/webserver.jar</tt>.
|
|
31
|
-
*
|
|
32
|
+
* <p/>
|
|
32
33
|
* When WarMain starts up, it extracts the webserver jar to a temporary
|
|
33
34
|
* directory, and creates a temporary work directory for the webapp. Both
|
|
34
35
|
* are deleted on exit.
|
|
35
|
-
*
|
|
36
|
+
* <p/>
|
|
36
37
|
* It then reads webserver.properties into a java.util.Properties object,
|
|
37
38
|
* creates a URL classloader holding the jar, and loads and invokes the
|
|
38
39
|
* <tt>main</tt> method of the main class mentioned in the properties.
|
|
39
|
-
*
|
|
40
|
+
* <p/>
|
|
40
41
|
* An example webserver.properties follows for Jetty. The <tt>args</tt>
|
|
41
42
|
* property indicates the names and ordering of other properties to be used
|
|
42
43
|
* as command-line arguments. The special tokens <tt>{{warfile}}</tt> and
|
|
@@ -63,7 +64,6 @@ import java.util.jar.JarEntry;
|
|
|
63
64
|
*/
|
|
64
65
|
public class WarMain extends JarMain {
|
|
65
66
|
|
|
66
|
-
static final String MAIN = '/' + WarMain.class.getName().replace('.', '/') + ".class";
|
|
67
67
|
static final String WEBSERVER_PROPERTIES = "/WEB-INF/webserver.properties";
|
|
68
68
|
static final String WEBSERVER_JAR = "/WEB-INF/webserver.jar";
|
|
69
69
|
static final String WEBSERVER_CONFIG = "/WEB-INF/webserver.xml";
|
|
@@ -85,8 +85,6 @@ public class WarMain extends JarMain {
|
|
|
85
85
|
private final String executable;
|
|
86
86
|
private final String[] executableArgv;
|
|
87
87
|
|
|
88
|
-
private File webroot;
|
|
89
|
-
|
|
90
88
|
WarMain(final String[] args) {
|
|
91
89
|
super(args);
|
|
92
90
|
final List<String> argsList = Arrays.asList(args);
|
|
@@ -115,36 +113,40 @@ public class WarMain extends JarMain {
|
|
|
115
113
|
}
|
|
116
114
|
}
|
|
117
115
|
|
|
118
|
-
private
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
116
|
+
private void launchWebServer() throws Exception {
|
|
117
|
+
File webroot = createWebRoot();
|
|
118
|
+
File jarFile = extractWebServerJar();
|
|
119
|
+
|
|
120
|
+
doLaunchWebServer(jarFile, webroot);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private File createWebRoot() throws IOException {
|
|
124
|
+
File warblerRoot = File.createTempFile("warbler", "webroot");
|
|
125
|
+
warblerRoot.delete();
|
|
126
|
+
warblerRoot.mkdirs();
|
|
127
|
+
closeables.add(() -> deleteAll(warblerRoot));
|
|
128
|
+
|
|
129
|
+
File webroot = new File(warblerRoot, new File(archive).getName());
|
|
130
|
+
debug("webroot directory is " + webroot.getPath());
|
|
131
|
+
return webroot;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private File extractWebServerJar() throws Exception {
|
|
125
135
|
File jarFile = File.createTempFile("webserver", ".jar");
|
|
126
136
|
jarFile.deleteOnExit();
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
while ((bytesRead = jarStream.read(buf)) != -1) {
|
|
132
|
-
outStream.write(buf, 0, bytesRead);
|
|
133
|
-
}
|
|
134
|
-
} finally {
|
|
135
|
-
jarStream.close();
|
|
136
|
-
outStream.close();
|
|
137
|
-
}
|
|
137
|
+
|
|
138
|
+
transferAndClose(
|
|
139
|
+
() -> new URI("jar", entryPath(WEBSERVER_JAR), null).toURL().openStream(),
|
|
140
|
+
() -> new FileOutputStream(jarFile));
|
|
138
141
|
debug("webserver.jar extracted to " + jarFile.getPath());
|
|
139
|
-
return jarFile
|
|
142
|
+
return jarFile;
|
|
140
143
|
}
|
|
141
144
|
|
|
142
|
-
private Properties getWebserverProperties() throws Exception {
|
|
145
|
+
private Properties getWebserverProperties(File webRoot) throws Exception {
|
|
143
146
|
Properties props = new Properties();
|
|
144
|
-
try {
|
|
145
|
-
InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES);
|
|
147
|
+
try (InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES)) {
|
|
146
148
|
if ( is != null ) props.load(is);
|
|
147
|
-
} catch (Exception
|
|
149
|
+
} catch (Exception ignore) { }
|
|
148
150
|
|
|
149
151
|
String port = getSystemProperty("warbler.port", getENV("PORT"));
|
|
150
152
|
port = port == null ? "8080" : port;
|
|
@@ -152,13 +154,13 @@ public class WarMain extends JarMain {
|
|
|
152
154
|
String webserverConfig = getSystemProperty("warbler.webserver_config", getENV("WARBLER_WEBSERVER_CONFIG"));
|
|
153
155
|
String embeddedWebserverConfig = new URI("jar", entryPath(WEBSERVER_CONFIG), null).toURL().toString();
|
|
154
156
|
webserverConfig = webserverConfig == null ? embeddedWebserverConfig : webserverConfig;
|
|
155
|
-
for ( Map.Entry entry : props.entrySet() ) {
|
|
157
|
+
for ( Map.Entry<Object, Object> entry : props.entrySet() ) {
|
|
156
158
|
String val = (String) entry.getValue();
|
|
157
159
|
val = val.replace("{{warfile}}", archive).
|
|
158
160
|
replace("{{port}}", port).
|
|
159
161
|
replace("{{host}}", host).
|
|
160
162
|
replace("{{config}}", webserverConfig).
|
|
161
|
-
replace("{{webroot}}",
|
|
163
|
+
replace("{{webroot}}", webRoot.getAbsolutePath());
|
|
162
164
|
entry.setValue(val);
|
|
163
165
|
}
|
|
164
166
|
|
|
@@ -172,10 +174,11 @@ public class WarMain extends JarMain {
|
|
|
172
174
|
return props;
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
|
|
178
|
+
private void doLaunchWebServer(File jar, File webRoot) throws Exception {
|
|
179
|
+
URLClassLoader loader = new URLClassLoader(new URL[] {jar.toURI().toURL()});
|
|
177
180
|
Thread.currentThread().setContextClassLoader(loader);
|
|
178
|
-
Properties props = getWebserverProperties();
|
|
181
|
+
Properties props = getWebserverProperties(webRoot);
|
|
179
182
|
String mainClass = props.getProperty("mainclass");
|
|
180
183
|
if (mainClass == null) {
|
|
181
184
|
throw new IllegalArgumentException("unknown webserver main class ("
|
|
@@ -183,7 +186,7 @@ public class WarMain extends JarMain {
|
|
|
183
186
|
+ " is missing 'mainclass' property)");
|
|
184
187
|
}
|
|
185
188
|
Class<?> klass = Class.forName(mainClass, true, loader);
|
|
186
|
-
Method main = klass.getDeclaredMethod("main",
|
|
189
|
+
Method main = klass.getDeclaredMethod("main", String[].class);
|
|
187
190
|
String[] newArgs = launchWebServerArguments(props);
|
|
188
191
|
debug("invoking webserver with: " + Arrays.deepToString(newArgs));
|
|
189
192
|
main.invoke(null, new Object[] { newArgs });
|
|
@@ -227,7 +230,7 @@ public class WarMain extends JarMain {
|
|
|
227
230
|
}
|
|
228
231
|
|
|
229
232
|
@Override
|
|
230
|
-
protected URL extractEntry(final JarEntry entry,
|
|
233
|
+
protected URL extractEntry(final JarEntry entry, String path) throws Exception {
|
|
231
234
|
// always extract but only return class-path entry URLs :
|
|
232
235
|
final URL entryURL = super.extractEntry(entry, path);
|
|
233
236
|
return path.endsWith(".jar") && path.startsWith("/lib/") ? entryURL : null;
|
|
@@ -256,7 +259,7 @@ public class WarMain extends JarMain {
|
|
|
256
259
|
|
|
257
260
|
invokeMethod(rubyInstanceConfig, "processArguments", (Object) arguments);
|
|
258
261
|
|
|
259
|
-
Object runtime = invokeMethod(
|
|
262
|
+
Object runtime = invokeMethod(provider, "getRuntime");
|
|
260
263
|
|
|
261
264
|
debug("loading resource: " + executablePath);
|
|
262
265
|
Object executableInput =
|
|
@@ -272,21 +275,6 @@ public class WarMain extends JarMain {
|
|
|
272
275
|
return ( outcome instanceof Number ) ? ( (Number) outcome ).intValue() : 0;
|
|
273
276
|
}
|
|
274
277
|
|
|
275
|
-
@Deprecated
|
|
276
|
-
protected String locateExecutable(final Object scriptingContainer) throws Exception {
|
|
277
|
-
if ( executable == null ) {
|
|
278
|
-
throw new IllegalStateException("no executable");
|
|
279
|
-
}
|
|
280
|
-
final File exec = new File(extractRoot, executable);
|
|
281
|
-
if ( exec.exists() ) {
|
|
282
|
-
return exec.getAbsolutePath();
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
final String script = locateExecutableScript(executable, executableScriptEnvPrefix());
|
|
286
|
-
return (String) invokeMethod(scriptingContainer, "runScriptlet", script);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
278
|
protected String locateExecutable(final Object scriptingContainer, final CharSequence envPreScript)
|
|
291
279
|
throws Exception {
|
|
292
280
|
if ( executable == null ) {
|
|
@@ -346,8 +334,7 @@ public class WarMain extends JarMain {
|
|
|
346
334
|
protected int start() throws Exception {
|
|
347
335
|
if ( executable == null ) {
|
|
348
336
|
try {
|
|
349
|
-
|
|
350
|
-
launchWebServer(server);
|
|
337
|
+
launchWebServer();
|
|
351
338
|
}
|
|
352
339
|
catch (FileNotFoundException e) {
|
|
353
340
|
final String msg = e.getMessage();
|
|
@@ -362,12 +349,6 @@ public class WarMain extends JarMain {
|
|
|
362
349
|
return super.start();
|
|
363
350
|
}
|
|
364
351
|
|
|
365
|
-
@Override
|
|
366
|
-
public void run() {
|
|
367
|
-
super.run();
|
|
368
|
-
if ( webroot != null ) delete(webroot.getParentFile());
|
|
369
|
-
}
|
|
370
|
-
|
|
371
352
|
public static void main(String[] args) {
|
|
372
353
|
doStart(new WarMain(args));
|
|
373
354
|
}
|
|
@@ -7,14 +7,7 @@
|
|
|
7
7
|
module Warbler
|
|
8
8
|
module BundlerHelper
|
|
9
9
|
def to_spec(spec)
|
|
10
|
-
|
|
11
|
-
# thus a `spec.respond_to?(:to_spec) ? spec.to_spec : spec` won't do :
|
|
12
|
-
if ::Bundler.const_defined?(:StubSpecification) # since Bundler 1.10.1
|
|
13
|
-
spec = spec.to_spec if spec.is_a?(::Bundler::StubSpecification)
|
|
14
|
-
else
|
|
15
|
-
spec = spec.to_spec if spec.respond_to?(:to_spec)
|
|
16
|
-
end
|
|
17
|
-
spec
|
|
10
|
+
spec.respond_to?(:to_spec) ? spec.to_spec : spec
|
|
18
11
|
end
|
|
19
12
|
module_function :to_spec
|
|
20
13
|
end
|