This repository has been archived by the owner on Jun 7, 2021. It is now read-only.
/
Runner.java
187 lines (163 loc) · 7.33 KB
/
Runner.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/**
* Copyright 2018 Red Hat, Inc, and individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.swarm.runner;
import org.wildfly.swarm.jdk.specific.ClassLoaders;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
import static java.lang.String.format;
import static java.util.Arrays.asList;
/**
* The class to execute when running Thorntail in the IDE.
*
* During execution, it resolves project's dependencies to ${user.home}
*
* It first generates an uber-jar and then executes it.
* The jar is generated from the IDE classpath by taking the Thorntail dependencies, generating an uber-jar in the similar way
* the thorntail-maven-plugin does and removing all the transitive dependencies of the Thorntail elements from WEB-INF/lib
* in the internal WAR.
*
* The following options are available to control the execution:
* <ul>
* <li>
* <b>thorntail.runner.preserve-jar</b> - keep the generated uber-jar when the application is stopped; might be useful for debugging
* </li>
* <li>
* <b>thorntail.runner.user-dependencies</b> - a comma-separated list of groupId:artifactId:version[:classifier] of artifacts
* to keep in WEB-INF/lib even though they are dependencies of Swarm elements
* </li>
* <li>
* <b>thorntail.runner.extra-dependencies</b> - a comma-separated list of groupId:artifactId[:packaging[:classifier]]:version of artifacts
* to add to the classpath (because the IDE didn't)
* </li>
* <li>
* <b>thorntail.runner.main-class</b> - user's main class replacing the default org.wildfly.swarm.Swarm class.
* Please note that using custom main class is discouraged.
* </li>
* <li>
* <b>thorntail.runner.webapp-location</b> - by default, Runner expects webapp in `src/main/webapp`. This property
* can be used to point to a different location of the webapp directory
* </li>
* <li>
* <b>thorntail.runner.repositories</b> - additional maven repositories to look for artifacts.
* By default Runner searches for artifacts in Maven Central, repository.jboss.org and maven.repository.redhat.com.
* Expects a comma separated list of repositoryUrl[#username#password].
* </li>
* <li>
* <b>thorntail.runner.ignore-default-repositories</b> - disable default configured maven repositories
* By default Runner searches for artifacts in Maven Central, repository.jboss.org and maven.repository.redhat.com.
* You can disable this for security reasons.
* </li>
* <li>
* <b>thorntail.runner.local-repository</b> - location of the local repository.
* By default, Runner will use ${user.home}/.m2/repository to store any resolved artifacts.
* This is the default Maven location. This property let's you choose a different location.
* </li>
* </ul>
*
*/
public class Runner {
private Runner() {
}
public static void main(String[] args) throws Exception {
System.out.printf("Starting Thorntail Runner. Runner caches will be stored in %s\n", RunnerConstants.CACHE_STORAGE_DIR);
URLClassLoader loader = createClassLoader();
run((Object) args, loader);
}
private static void run(Object args, URLClassLoader loader) throws Exception {
callWithClassloader(loader,
"org.wildfly.swarm.bootstrap.Main",
"main",
new Class<?>[]{String[].class},
args);
}
private static <T> T callWithClassloader(ClassLoader loader,
String className,
String methodName,
Class<?>[] argumentTypes,
Object... arguments) throws Exception {
Thread.currentThread().setContextClassLoader(loader);
Class<?> aClass = loader.loadClass(className);
Method method = aClass.getMethod(methodName, argumentTypes);
return (T) method.invoke(null, arguments);
}
private static URLClassLoader createClassLoader() throws Exception {
File fatJar = File.createTempFile("thorntail-user-app", ".jar");
buildJar(fatJar);
if (RunnerConstants.PRESERVE_JAR == null) {
System.out.println("Built " + fatJar.getAbsolutePath() + ", the file will be deleted on shutdown. To keep it, use -Dthorntail.runner.preserve-jar");
fatJar.deleteOnExit();
}
URL jarUrl = fatJar.toURI().toURL();
return new URLClassLoader(new URL[]{jarUrl}, ClassLoaders.getPlatformClassLoader());
}
private static void buildJar(File fatJar) throws IOException, InterruptedException {
String classpath = System.getProperty("java.class.path");
List<String> command = buildCommand(fatJar);
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.environment().put("CLASSPATH", classpath);
Process fatJarBuilder = processBuilder
.inheritIO()
.start();
int exitCode = fatJarBuilder.waitFor();
if (exitCode != 0) {
throw new RuntimeException("Failed to generate the uber jar.");
}
}
/*
builds a command like:
/my/path/to/java -Dall -Dsystem=properties JarBuilderClassName pathToTargetJar
*/
private static List<String> buildCommand(File fatJar) {
List<String> command = new ArrayList<>(Collections.singleton(javaCommand()));
command.addAll(properties());
command.addAll(asList(
FatJarBuilder.class.getCanonicalName(),
fatJar.getAbsolutePath()
));
return command;
}
private static Collection<String> properties() {
return System.getProperties()
.entrySet()
.stream()
.map(Runner::propertyToString)
.collect(Collectors.toList());
}
private static String propertyToString(Map.Entry<Object, Object> property) {
return property.getValue() == null
? format("-D%s", property.getKey())
: format("-D%s=%s", property.getKey(), property.getValue());
}
private static String javaCommand() {
Path javaBinPath = Paths.get(System.getProperty("java.home"), "bin");
File javaExecutable = javaBinPath.resolve("java").toFile();
if (!javaExecutable.exists()) {
javaExecutable = javaBinPath.resolve("java.exe").toFile();
}
return javaExecutable.getAbsolutePath();
}
}