use of io.quarkus.bootstrap.app.StartupAction in project quarkus by quarkusio.
the class QuarkusDeployableContainer method deploy.
@SuppressWarnings("rawtypes")
@Override
public ProtocolMetaData deploy(Archive<?> archive) throws DeploymentException {
old = Thread.currentThread().getContextClassLoader();
if (testClass.get() == null) {
throw new IllegalStateException("Test class not available");
}
Class testJavaClass = testClass.get().getJavaClass();
// some TCK tests embed random libraries such as old versions of Jackson databind
// this breaks quarkus, so we just skip them
boolean skipLibraries = Boolean.getBoolean("io.quarkus.arquillian.skip-libraries");
try {
// Export the test archive
Path tmpLocation = Files.createTempDirectory("quarkus-arquillian-test");
deploymentLocation.set(tmpLocation);
archive.as(ExplodedExporter.class).exportExplodedInto(tmpLocation.toFile());
Path appLocation;
Set<Path> libraries = new HashSet<>();
if (archive instanceof WebArchive) {
// Quarkus does not support the WAR layout and so adapt the layout (similarly to quarkus-war-launcher)
appLocation = tmpLocation.resolve("app").toAbsolutePath();
// WEB-INF/lib -> lib/
if (!skipLibraries) {
if (Files.exists(tmpLocation.resolve("WEB-INF/lib"))) {
Files.move(tmpLocation.resolve("WEB-INF/lib"), tmpLocation.resolve("lib"));
}
}
// WEB-INF/classes -> archive/
if (Files.exists(tmpLocation.resolve("WEB-INF/classes"))) {
Files.move(tmpLocation.resolve("WEB-INF/classes"), appLocation);
} else {
Files.createDirectory(appLocation);
}
// META-INF -> archive/META-INF/
if (Files.exists(tmpLocation.resolve("META-INF"))) {
if (Files.exists(appLocation.resolve("META-INF"))) {
// Target directory not empty.
try (Stream<Path> fileTreeElements = Files.walk(tmpLocation.resolve("META-INF"), 2)) {
fileTreeElements.forEach(p -> {
try {
Files.createFile(p);
} catch (FileAlreadyExistsException faee) {
// Do Nothing
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
} else {
Files.move(tmpLocation.resolve("META-INF"), appLocation.resolve("META-INF"));
}
}
// WEB-INF -> archive/WEB-INF
if (Files.exists(tmpLocation.resolve("WEB-INF"))) {
Files.move(tmpLocation.resolve("WEB-INF"), appLocation.resolve("WEB-INF"));
}
// Collect all libraries
if (Files.exists(tmpLocation.resolve("lib"))) {
try (Stream<Path> libs = Files.walk(tmpLocation.resolve("lib"), 1)) {
libs.forEach((i) -> {
if (i.getFileName().toString().endsWith(".jar")) {
libraries.add(i);
}
});
}
}
} else {
appLocation = tmpLocation;
}
List<Consumer<BuildChainBuilder>> customizers = new ArrayList<>();
// Test class is a bean
customizers.add(new Consumer<BuildChainBuilder>() {
@Override
public void accept(BuildChainBuilder buildChainBuilder) {
buildChainBuilder.addBuildStep(new BuildStep() {
@Override
public void execute(BuildContext context) {
context.produce(AdditionalBeanBuildItem.unremovableOf(testJavaClass));
}
}).produces(AdditionalBeanBuildItem.class).build();
}
});
QuarkusBootstrap.Builder bootstrapBuilder = QuarkusBootstrap.builder().setApplicationRoot(appLocation).setProjectRoot(appLocation).setIsolateDeployment(false).setFlatClassPath(true).setMode(QuarkusBootstrap.Mode.TEST);
for (Path i : libraries) {
bootstrapBuilder.addAdditionalApplicationArchive(new AdditionalDependency(i, false, true));
}
// Path testLocation = PathTestHelper.getTestClassesLocation(testJavaClass);
// bootstrapBuilder.setProjectRoot(PathTestHelper.getTestClassesLocation(testJavaClass));
CuratedApplication curatedApplication = bootstrapBuilder.build().bootstrap();
AugmentAction augmentAction = new AugmentActionImpl(curatedApplication, customizers);
StartupAction app = augmentAction.createInitialRuntimeApplication();
RunningQuarkusApplication runningQuarkusApplication = app.run();
appClassloader.set(runningQuarkusApplication.getClassLoader());
runningApp.set(runningQuarkusApplication);
Thread.currentThread().setContextClassLoader(runningQuarkusApplication.getClassLoader());
// Instantiate the real test instance
testInstance = TestInstantiator.instantiateTest(testJavaClass, runningQuarkusApplication.getClassLoader());
// its pretty bogus
if (Boolean.getBoolean("io.quarkus.arquillian.copy-fields")) {
Class<?> dest = testInstance.getClass();
Class<?> source = testClass.get().getJavaClass();
while (source != Object.class) {
for (Field f : source.getDeclaredFields()) {
try {
if (Modifier.isStatic(f.getModifiers()) && !Modifier.isFinal(f.getModifiers())) {
Field df = dest.getDeclaredField(f.getName());
df.setAccessible(true);
f.setAccessible(true);
df.set(null, f.get(null));
}
} catch (Exception e) {
LOGGER.error("Failed to copy static field", e);
}
}
source = source.getSuperclass();
dest = dest.getSuperclass();
}
}
} catch (Throwable t) {
// clone the exception into the correct class loader
Throwable nt;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (ObjectOutputStream a = new ObjectOutputStream(out)) {
a.writeObject(t);
a.close();
nt = (Throwable) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
} catch (Exception e) {
throw new DeploymentException("Unable to start the runtime runner", t);
}
throw new DeploymentException("Unable to start the runtime runner", nt);
} finally {
Thread.currentThread().setContextClassLoader(old);
}
ProtocolMetaData metadata = new ProtocolMetaData();
// TODO: fix this
String testUri = TestHTTPResourceManager.getUri(runningApp.get());
System.setProperty("test.url", testUri);
URI uri = URI.create(testUri);
HTTPContext httpContext = new HTTPContext(uri.getHost(), uri.getPort());
// This is to work around https://github.com/arquillian/arquillian-core/issues/216
httpContext.add(new Servlet("dummy", "/"));
metadata.addContext(httpContext);
return metadata;
}
use of io.quarkus.bootstrap.app.StartupAction in project quarkus by quarkusio.
the class QuarkusTestExtension method doJavaStart.
private ExtensionState doJavaStart(ExtensionContext context, Class<? extends QuarkusTestProfile> profile) throws Throwable {
TracingHandler.quarkusStarting();
hangDetectionExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Quarkus hang detection timer thread");
}
});
String time = "10m";
// config is not established yet
// we can only read from system properties
String sysPropString = System.getProperty(QUARKUS_TEST_HANG_DETECTION_TIMEOUT);
if (sysPropString != null) {
time = sysPropString;
}
hangTimeout = new DurationConverter().convert(time);
hangTaskKey = hangDetectionExecutor.schedule(hangDetectionTask, hangTimeout.toMillis(), TimeUnit.MILLISECONDS);
quarkusTestProfile = profile;
Class<?> requiredTestClass = context.getRequiredTestClass();
Closeable testResourceManager = null;
try {
final LinkedBlockingDeque<Runnable> shutdownTasks = new LinkedBlockingDeque<>();
PrepareResult result = createAugmentor(context, profile, shutdownTasks);
AugmentAction augmentAction = result.augmentAction;
QuarkusTestProfile profileInstance = result.profileInstance;
testHttpEndpointProviders = TestHttpEndpointProvider.load();
StartupAction startupAction = augmentAction.createInitialRuntimeApplication();
Thread.currentThread().setContextClassLoader(startupAction.getClassLoader());
populateDeepCloneField(startupAction);
// must be done after the TCCL has been set
testResourceManager = (Closeable) startupAction.getClassLoader().loadClass(TestResourceManager.class.getName()).getConstructor(Class.class, Class.class, List.class, boolean.class, Map.class, Optional.class).newInstance(requiredTestClass, profile != null ? profile : null, getAdditionalTestResources(profileInstance, startupAction.getClassLoader()), profileInstance != null && profileInstance.disableGlobalTestResources(), startupAction.getDevServicesProperties(), Optional.empty());
testResourceManager.getClass().getMethod("init", String.class).invoke(testResourceManager, profile != null ? profile.getName() : null);
Map<String, String> properties = (Map<String, String>) testResourceManager.getClass().getMethod("start").invoke(testResourceManager);
startupAction.overrideConfig(properties);
hasPerTestResources = (boolean) testResourceManager.getClass().getMethod("hasPerTestResources").invoke(testResourceManager);
populateCallbacks(startupAction.getClassLoader());
populateTestMethodInvokers(startupAction.getClassLoader());
if (profileInstance == null || !profileInstance.runMainMethod()) {
runningQuarkusApplication = startupAction.run(profileInstance == null ? new String[0] : profileInstance.commandLineParameters());
} else {
Class<?> lifecycleManager = Class.forName(ApplicationLifecycleManager.class.getName(), true, startupAction.getClassLoader());
lifecycleManager.getDeclaredMethod("setDefaultExitCodeHandler", Consumer.class).invoke(null, (Consumer<Integer>) integer -> {
});
runningQuarkusApplication = startupAction.runMainClass(profileInstance.commandLineParameters());
}
String patternString = runningQuarkusApplication.getConfigValue("quarkus.test.class-clone-pattern", String.class).orElse("java\\..*");
clonePattern = Pattern.compile(patternString);
TracingHandler.quarkusStarted();
if (hangTaskKey != null) {
hangTaskKey.cancel(false);
hangTimeout = runningQuarkusApplication.getConfigValue(QUARKUS_TEST_HANG_DETECTION_TIMEOUT, Duration.class).orElse(Duration.of(10, ChronoUnit.MINUTES));
hangTaskKey = hangDetectionExecutor.schedule(hangDetectionTask, hangTimeout.toMillis(), TimeUnit.MILLISECONDS);
}
ConfigProviderResolver.setInstance(new RunningAppConfigResolver(runningQuarkusApplication));
RestorableSystemProperties restorableSystemProperties = RestorableSystemProperties.setProperties(Collections.singletonMap("test.url", TestHTTPResourceManager.getUri(runningQuarkusApplication)));
Closeable tm = testResourceManager;
Closeable shutdownTask = new Closeable() {
@Override
public void close() throws IOException {
TracingHandler.quarkusStopping();
try {
runningQuarkusApplication.close();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
TracingHandler.quarkusStopped();
try {
while (!shutdownTasks.isEmpty()) {
shutdownTasks.pop().run();
}
} finally {
try {
tm.close();
} finally {
restorableSystemProperties.close();
GroovyCacheCleaner.clearGroovyCache();
shutdownHangDetection();
}
}
try {
TestClassIndexer.removeIndex(requiredTestClass);
} catch (Exception ignored) {
}
}
}
};
ExtensionState state = new ExtensionState(testResourceManager, shutdownTask);
return state;
} catch (Throwable e) {
if (!InitialConfigurator.DELAYED_HANDLER.isActivated()) {
activateLogging();
}
try {
if (testResourceManager != null) {
testResourceManager.close();
}
} catch (Exception ex) {
e.addSuppressed(ex);
}
throw e;
} finally {
if (originalCl != null) {
Thread.currentThread().setContextClassLoader(originalCl);
}
}
}
use of io.quarkus.bootstrap.app.StartupAction in project quarkus by quarkusio.
the class IsolatedDevModeMain method firstStart.
private synchronized void firstStart(QuarkusClassLoader deploymentClassLoader, List<CodeGenData> codeGens) {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
// ok, we have resolved all the deps
try {
StartupAction start = augmentAction.createInitialRuntimeApplication();
// this is a bit yuck, but we need replace the default
// exit handler in the runtime class loader
// TODO: look at implementing a common core classloader, that removes the need for this sort of crappy hack
curatedApplication.getBaseRuntimeClassLoader().loadClass(ApplicationLifecycleManager.class.getName()).getMethod("setDefaultExitCodeHandler", Consumer.class).invoke(null, new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
if (restarting || ApplicationLifecycleManager.isVmShuttingDown() || context.isAbortOnFailedStart() || context.isTest()) {
return;
}
if (consoleContext == null) {
consoleContext = ConsoleStateManager.INSTANCE.createContext("Completed Application");
}
// this sucks, but when we get here logging is gone
// so we just setup basic console logging
InitialConfigurator.DELAYED_HANDLER.addHandler(new ConsoleHandler(ConsoleHandler.Target.SYSTEM_OUT, new ColorPatternFormatter("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n")));
consoleContext.reset(new ConsoleCommand(' ', "Restarts the application", "to restart", 0, null, () -> {
consoleContext.reset();
RuntimeUpdatesProcessor.INSTANCE.doScan(true, true);
}), new ConsoleCommand('e', "Edits the command line parameters and restarts", "to edit command line args (currently '" + MessageFormat.GREEN + String.join(" ", context.getArgs()) + MessageFormat.RESET + "')", 100, new ConsoleCommand.HelpState(() -> BLUE, () -> String.join(" ", context.getArgs())), new Consumer<String>() {
@Override
public void accept(String args) {
try {
context.setArgs(CommandLineUtils.translateCommandline(args));
} catch (CommandLineException e) {
log.error("Failed to parse command line", e);
return;
}
consoleContext.reset();
RuntimeUpdatesProcessor.INSTANCE.doScan(true, true);
}
}));
}
});
startCodeGenWatcher(deploymentClassLoader, codeGens, context.getBuildSystemProperties());
runner = start.runMainClass(context.getArgs());
RuntimeUpdatesProcessor.INSTANCE.setConfiguredInstrumentationEnabled(runner.getConfigValue("quarkus.live-reload.instrumentation", Boolean.class).orElse(false));
firstStartCompleted = true;
for (DevModeListener listener : ServiceLoader.load(DevModeListener.class)) {
listeners.add(listener);
}
listeners.sort(Comparator.comparingInt(DevModeListener::order));
for (DevModeListener listener : ServiceLoader.load(DevModeListener.class)) {
try {
listener.afterFirstStart(runner);
} catch (Exception e) {
log.warn("Unable to invoke 'afterFirstStart' of " + listener.getClass(), e);
}
}
} catch (Throwable t) {
Throwable rootCause = t;
while (rootCause.getCause() != null) {
rootCause = rootCause.getCause();
}
if (!(rootCause instanceof BindException)) {
deploymentProblem = t;
if (!context.isAbortOnFailedStart()) {
// we need to set this here, while we still have the correct TCCL
// this is so the config is still valid, and we can read HTTP config from application.properties
log.info("Attempting to start live reload endpoint to recover from previous Quarkus startup failure");
if (RuntimeUpdatesProcessor.INSTANCE != null) {
Thread.currentThread().setContextClassLoader(curatedApplication.getBaseRuntimeClassLoader());
try {
if (!InitialConfigurator.DELAYED_HANDLER.isActivated()) {
Class<?> cl = Thread.currentThread().getContextClassLoader().loadClass(LoggingSetupRecorder.class.getName());
cl.getMethod("handleFailedStart").invoke(null);
}
RuntimeUpdatesProcessor.INSTANCE.startupFailed();
// this exception has already been logged, so don't log it again
if (!(t instanceof ApplicationStartException)) {
log.error("Failed to start quarkus", t);
}
} catch (Exception e) {
close();
log.error("Failed to start quarkus", t);
log.error("Failed to recover after failed start", e);
// this is the end of the road, we just exit
// generally we only hit this if something is already listening on the HTTP port
// or the system config is so broken we can't start HTTP
System.exit(1);
}
}
} else {
log.error("Failed to start quarkus", t);
}
}
}
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
use of io.quarkus.bootstrap.app.StartupAction in project quarkus by quarkusio.
the class IsolatedDevModeMain method restartApp.
public synchronized void restartApp(Set<String> changedResources, ClassChangeInformation classChangeInformation) {
restarting = true;
if (consoleContext != null) {
consoleContext.reset();
}
stop();
Timing.restart(curatedApplication.getAugmentClassLoader());
deploymentProblem = null;
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
// ok, we have resolved all the deps
try {
StartupAction start = augmentAction.reloadExistingApplication(firstStartCompleted, changedResources, classChangeInformation);
runner = start.runMainClass(context.getArgs());
firstStartCompleted = true;
} catch (Throwable t) {
deploymentProblem = t;
Throwable rootCause = t;
while (rootCause.getCause() != null) {
rootCause = rootCause.getCause();
}
if (!(rootCause instanceof BindException)) {
log.error("Failed to start quarkus", t);
Thread.currentThread().setContextClassLoader(curatedApplication.getAugmentClassLoader());
LoggingSetupRecorder.handleFailedStart();
}
}
} finally {
restarting = false;
Thread.currentThread().setContextClassLoader(old);
}
}
use of io.quarkus.bootstrap.app.StartupAction in project quarkus by quarkusio.
the class QuarkusMainTestExtension method doJavaStart.
private int doJavaStart(ExtensionContext context, Class<? extends QuarkusTestProfile> profile, String[] arguments) throws Exception {
TracingHandler.quarkusStarting();
Closeable testResourceManager = null;
try {
StartupAction startupAction = prepareResult.augmentAction.createInitialRuntimeApplication();
Thread.currentThread().setContextClassLoader(startupAction.getClassLoader());
QuarkusConsole.installRedirects();
flushAllLoggers();
installLoggerRedirect();
QuarkusTestProfile profileInstance = prepareResult.profileInstance;
// must be done after the TCCL has been set
testResourceManager = (Closeable) startupAction.getClassLoader().loadClass(TestResourceManager.class.getName()).getConstructor(Class.class, Class.class, List.class, boolean.class, Map.class, Optional.class).newInstance(context.getRequiredTestClass(), profile != null ? profile : null, getAdditionalTestResources(profileInstance, startupAction.getClassLoader()), profileInstance != null && profileInstance.disableGlobalTestResources(), startupAction.getDevServicesProperties(), Optional.empty());
testResourceManager.getClass().getMethod("init", String.class).invoke(testResourceManager, profile != null ? profile.getName() : null);
Map<String, String> properties = (Map<String, String>) testResourceManager.getClass().getMethod("start").invoke(testResourceManager);
startupAction.overrideConfig(properties);
hasPerTestResources = (boolean) testResourceManager.getClass().getMethod("hasPerTestResources").invoke(testResourceManager);
testResourceManager.getClass().getMethod("inject", Object.class).invoke(testResourceManager, context.getRequiredTestInstance());
var result = startupAction.runMainClassBlocking(arguments);
flushAllLoggers();
return result;
} catch (Throwable e) {
if (!InitialConfigurator.DELAYED_HANDLER.isActivated()) {
activateLogging();
}
try {
if (testResourceManager != null) {
testResourceManager.close();
}
} catch (Exception ex) {
e.addSuppressed(ex);
}
throw e;
} finally {
uninstallLoggerRedirect();
QuarkusConsole.uninstallRedirects();
if (originalCl != null) {
Thread.currentThread().setContextClassLoader(originalCl);
}
}
}
Aggregations