diff --git a/quarkus/pom.xml b/quarkus/pom.xml index 7b6377811d..4e6df73cb5 100755 --- a/quarkus/pom.xml +++ b/quarkus/pom.xml @@ -56,6 +56,8 @@ pom import + + org.hibernate hibernate-core @@ -100,33 +102,6 @@ - - - org.hibernate - hibernate-core - - - org.infinispan - infinispan-core - - - org.infinispan - infinispan-commons - - - - - - - - org.jboss.jandex - jandex-maven-plugin - 1.0.8 - - - - - deployment runtime diff --git a/quarkus/runtime/pom.xml b/quarkus/runtime/pom.xml index e07f9fed9f..8bf065c059 100644 --- a/quarkus/runtime/pom.xml +++ b/quarkus/runtime/pom.xml @@ -441,6 +441,14 @@ org.liquibase liquibase-core + + org.infinispan + infinispan-commons + + + org.infinispan + infinispan-core + junit junit diff --git a/quarkus/runtime/src/main/java/org/keycloak/QuarkusKeycloakApplication.java b/quarkus/runtime/src/main/java/org/keycloak/QuarkusKeycloakApplication.java index 9964c7099c..fb731cd1ef 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/QuarkusKeycloakApplication.java +++ b/quarkus/runtime/src/main/java/org/keycloak/QuarkusKeycloakApplication.java @@ -14,6 +14,7 @@ import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters; import org.jboss.resteasy.spi.ResteasyDeployment; import org.keycloak.common.util.Resteasy; import org.keycloak.models.utils.PostMigrationEvent; +import org.keycloak.provider.quarkus.QuarkusPlatform; import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.QuarkusWelcomeResource; import org.keycloak.services.resources.WelcomeResource; @@ -26,9 +27,13 @@ public class QuarkusKeycloakApplication extends KeycloakApplication { @Override protected void startup() { - forceEntityManagerInitialization(); - initializeKeycloakSessionFactory(); - setupScheduledTasks(sessionFactory); + try { + forceEntityManagerInitialization(); + initializeKeycloakSessionFactory(); + setupScheduledTasks(sessionFactory); + } catch (Throwable cause) { + QuarkusPlatform.exitOnError(cause); + } } @Override diff --git a/quarkus/runtime/src/main/java/org/keycloak/cli/Picocli.java b/quarkus/runtime/src/main/java/org/keycloak/cli/Picocli.java index 593f27896a..0615f0e576 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/cli/Picocli.java +++ b/quarkus/runtime/src/main/java/org/keycloak/cli/Picocli.java @@ -28,7 +28,7 @@ import org.keycloak.common.Profile; import org.keycloak.configuration.PropertyMapper; import org.keycloak.configuration.PropertyMappers; import org.keycloak.platform.Platform; -import org.keycloak.provider.quarkus.QuarkusConfigurationException; +import org.keycloak.provider.quarkus.InitializationException; import org.keycloak.provider.quarkus.QuarkusPlatform; import org.keycloak.util.Environment; import picocli.CommandLine; @@ -136,16 +136,16 @@ final class Picocli { if (throwable != null) { boolean verbose = cliArgs.stream().anyMatch((arg) -> "--verbose".equals(arg)); - if (throwable instanceof QuarkusConfigurationException) { - QuarkusConfigurationException quarkusConfigException = (QuarkusConfigurationException) throwable; - if (quarkusConfigException.getSuppressed() == null || quarkusConfigException.getSuppressed().length == 0) { - dumpException(cmd, quarkusConfigException, verbose); - } else if (quarkusConfigException.getSuppressed().length == 1) { - dumpException(cmd, quarkusConfigException.getSuppressed()[0], verbose); + if (throwable instanceof InitializationException) { + InitializationException initializationException = (InitializationException) throwable; + if (initializationException.getSuppressed() == null || initializationException.getSuppressed().length == 0) { + dumpException(cmd, initializationException, verbose); + } else if (initializationException.getSuppressed().length == 1) { + dumpException(cmd, initializationException.getSuppressed()[0], verbose); } else { logError(cmd, "ERROR: Multiple configuration errors during startup"); int counter = 0; - for (Throwable inner : quarkusConfigException.getSuppressed()) { + for (Throwable inner : initializationException.getSuppressed()) { counter++; logError(cmd, "ERROR " + counter); dumpException(cmd, inner, verbose); diff --git a/quarkus/runtime/src/main/java/org/keycloak/configuration/PropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/configuration/PropertyMappers.java index 0fe943d335..6452893b03 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/configuration/PropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/configuration/PropertyMappers.java @@ -21,6 +21,7 @@ import static org.keycloak.configuration.PropertyMapper.MAPPERS; import static org.keycloak.configuration.PropertyMapper.create; import static org.keycloak.configuration.PropertyMapper.createWithDefault; import static org.keycloak.configuration.PropertyMapper.forBuildTimeProperty; +import static org.keycloak.provider.quarkus.QuarkusPlatform.addInitializationException; import java.io.File; import java.nio.file.Paths; @@ -67,7 +68,7 @@ public final class PropertyMappers { } if (proceed == null || proceed.getValue() == null) { - addDeferredConfigurationException(Messages.httpsConfigurationNotSet()); + addInitializationException(Messages.httpsConfigurationNotSet()); } } @@ -114,7 +115,7 @@ public final class PropertyMappers { case "passthrough": return "true"; } - addDeferredConfigurationException(Messages.invalidProxyMode(mode)); + addInitializationException(Messages.invalidProxyMode(mode)); return "false"; }, "The proxy mode if the server is behind a reverse proxy. Possible values are: none, edge, reencrypt, and passthrough."); } @@ -167,7 +168,7 @@ public final class PropertyMappers { case "postgres-10": return "postgresql"; } - addDeferredConfigurationException(invalidDatabaseVendor(db, "h2-file", "h2-mem", "mariadb", "mysql", "postgres", "postgres-95", "postgres-10")); + addInitializationException(invalidDatabaseVendor(db, "h2-file", "h2-mem", "mariadb", "mysql", "postgres", "postgres-95", "postgres-10")); return "h2"; }, "The database vendor. Possible values are: h2-mem, h2-file, mariadb, mysql, postgres95, postgres10."); create("db", "quarkus.datasource.jdbc.transactions", (db, context) -> "xa", null); @@ -197,16 +198,7 @@ public final class PropertyMappers { } private static void configureClustering() { - createWithDefault("cluster", "kc.spi.connections-infinispan.default.config-file", "placeholder", (value, context) -> { - - if ("placeholder".equals(value)) { - // Clustering is disabled by default for the "dev" profile. Otherwise enabled - value = ("dev".equalsIgnoreCase(ProfileManager.getActiveProfile())) ? "local" : "default"; - } - - return "cluster-" + value + ".xml"; - - }, "Specifies clustering configuration. The specified value points to the infinispan configuration file prefixed with the 'cluster-` " + createWithDefault("cluster", "kc.spi.connections-infinispan.default.config-file", "default", (value, context) -> "cluster-" + value + ".xml", "Specifies clustering configuration. The specified value points to the infinispan configuration file prefixed with the 'cluster-` " + "inside the distribution configuration directory. Supported values out of the box are 'local' and 'cluster'. Value 'local' points to the file cluster-local.xml and " + "effectively disables clustering and use infinispan caches in the local mode. Value 'default' points to the file cluster-default.xml, which has clustering enabled for infinispan caches."); create("cluster-stack", "kc.spi.connections-infinispan.default.stack", "Specified the default stack to use for cluster communication and node discovery. Possible values are: tcp, udp, kubernetes, ec2."); @@ -268,10 +260,4 @@ public final class PropertyMappers { } }).findFirst().orElse(null); } - - // Exception to be thrown later, so that we can properly log it and collect all possible configuration issues (not just the first one) - private static void addDeferredConfigurationException(Exception e) { - QuarkusPlatform quarkusPlatform = (QuarkusPlatform) Platform.getPlatform(); - quarkusPlatform.addDeferredException(e); - } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusConfigurationException.java b/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/InitializationException.java similarity index 93% rename from quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusConfigurationException.java rename to quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/InitializationException.java index f36ccd3bee..a2d17178a0 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusConfigurationException.java +++ b/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/InitializationException.java @@ -24,5 +24,5 @@ package org.keycloak.provider.quarkus; * * @author Marek Posolda */ -public class QuarkusConfigurationException extends RuntimeException { +public class InitializationException extends RuntimeException { } diff --git a/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java b/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java index fa3d722238..c0226a5af9 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java +++ b/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java @@ -40,16 +40,7 @@ public class QuarkusLifecycleObserver { void onStartupEvent(@Observes StartupEvent event) { QuarkusPlatform platform = (QuarkusPlatform) Platform.getPlatform(); platform.started(); - - // Check if we had any exceptions during configuration phase - if (!platform.getDeferredExceptions().isEmpty()) { - QuarkusConfigurationException quarkusException = new QuarkusConfigurationException(); - for (Throwable inner : platform.getDeferredExceptions()) { - quarkusException.addSuppressed(inner); - } - throw quarkusException; - } - + QuarkusPlatform.exitOnError(); Runnable startupHook = platform.startupHook; if (startupHook != null) { diff --git a/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusPlatform.java b/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusPlatform.java index 1510937596..c76255d030 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusPlatform.java +++ b/quarkus/runtime/src/main/java/org/keycloak/provider/quarkus/QuarkusPlatform.java @@ -21,10 +21,48 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; +import org.keycloak.platform.Platform; import org.keycloak.platform.PlatformProvider; public class QuarkusPlatform implements PlatformProvider { + public static void addInitializationException(Throwable throwable) { + QuarkusPlatform platform = (QuarkusPlatform) Platform.getPlatform(); + platform.addDeferredException(throwable); + } + + /** + *

Throws a {@link InitializationException} exception to indicate errors during the startup. + * + *

Calling this method after the server is started has no effect but just the exception being thrown. + * + * @throws InitializationException the exception holding all errors during startup. + */ + public static void exitOnError() throws InitializationException { + QuarkusPlatform platform = (QuarkusPlatform) Platform.getPlatform(); + + // Check if we had any exceptions during initialization phase + if (!platform.getDeferredExceptions().isEmpty()) { + InitializationException quarkusException = new InitializationException(); + for (Throwable inner : platform.getDeferredExceptions()) { + quarkusException.addSuppressed(inner); + } + throw quarkusException; + } + } + + /** + * Similar behavior as per {@code #exitOnError} but convenient to throw a {@link InitializationException} with a single + * {@code cause} + * + * @param cause the cause + * @throws InitializationException the initialization exception with the given {@code cause}. + */ + public static void exitOnError(Throwable cause) throws InitializationException{ + addInitializationException(cause); + exitOnError(); + } + Runnable startupHook; Runnable shutdownHook; @@ -49,7 +87,7 @@ public class QuarkusPlatform implements PlatformProvider { /** * Called when Quarkus platform is started */ - public void started() { + void started() { this.started.set(true); } @@ -62,11 +100,11 @@ public class QuarkusPlatform implements PlatformProvider { * * @param t */ - public void addDeferredException(Throwable t) { + private void addDeferredException(Throwable t) { deferredExceptions.add(t); } - public List getDeferredExceptions() { + List getDeferredExceptions() { return deferredExceptions; } diff --git a/quarkus/runtime/src/test/java/org/keycloak/provider/quarkus/ConfigurationTest.java b/quarkus/runtime/src/test/java/org/keycloak/provider/quarkus/ConfigurationTest.java index dfe7018b75..7c2b03237f 100644 --- a/quarkus/runtime/src/test/java/org/keycloak/provider/quarkus/ConfigurationTest.java +++ b/quarkus/runtime/src/test/java/org/keycloak/provider/quarkus/ConfigurationTest.java @@ -234,8 +234,6 @@ public class ConfigurationTest { public void testClusterConfig() { // Cluster enabled by default, but disabled for the "dev" profile Assert.assertEquals("cluster-default.xml", initConfig("connectionsInfinispan", "default").get("configFile")); - System.setProperty("kc.profile", "dev"); - Assert.assertEquals("cluster-local.xml", initConfig("connectionsInfinispan", "default").get("configFile")); // If explicitly set, then it is always used regardless of the profile System.clearProperty("kc.profile"); diff --git a/quarkus/server/pom.xml b/quarkus/server/pom.xml index 2a24c5151c..f13145b16a 100644 --- a/quarkus/server/pom.xml +++ b/quarkus/server/pom.xml @@ -64,50 +64,4 @@ - - - native - - - native - - - - - - io.quarkus - quarkus-maven-plugin - ${quarkus.version} - - - - native-image - - - true - - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - - - - - - - - - diff --git a/quarkus/server/src/main/resources/META-INF/keycloak.properties b/quarkus/server/src/main/resources/META-INF/keycloak.properties index 4551da2232..93c0d102d5 100644 --- a/quarkus/server/src/main/resources/META-INF/keycloak.properties +++ b/quarkus/server/src/main/resources/META-INF/keycloak.properties @@ -4,4 +4,5 @@ db=h2-file # Default, and insecure, and non-production grade configuration for the development profile %dev.http.enabled=true %dev.db.username = sa -%dev.db.password = keycloak \ No newline at end of file +%dev.db.password = keycloak +%dev.cluster=local \ No newline at end of file