From f3c3bb50016e818d9f035e72a83d1cc26e0db9a2 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Tue, 15 Feb 2022 08:09:14 -0300 Subject: [PATCH] Removing unnecessary code paths during startup (#10131) Closes #10130 --- quarkus/deployment/pom.xml | 13 ------ quarkus/runtime/pom.xml | 4 +- .../quarkus/runtime/KeycloakClassLoader.java | 42 +++++++++++++++++++ .../quarkus/runtime/KeycloakMain.java | 10 +++-- .../quarkus/runtime/KeycloakRecorder.java | 21 +--------- .../QuarkusJpaConnectionProviderFactory.java | 8 ++-- .../infinispan/CacheManagerFactory.java | 29 +++++++++++-- .../WebAuthnCredentialProviderFactory.java | 9 +++- 8 files changed, 91 insertions(+), 45 deletions(-) create mode 100644 quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakClassLoader.java diff --git a/quarkus/deployment/pom.xml b/quarkus/deployment/pom.xml index c391fd28491..20f84457053 100644 --- a/quarkus/deployment/pom.xml +++ b/quarkus/deployment/pom.xml @@ -78,19 +78,6 @@ io.quarkus quarkus-smallrye-metrics-deployment - - - io.quarkus - quarkus-infinispan-client-deployment - - - org.wildfly.security - wildfly-elytron-sasl-gssapi - - - org.wildfly.security - wildfly-elytron-sasl-gs2 - io.quarkiverse.vault quarkus-vault-deployment diff --git a/quarkus/runtime/pom.xml b/quarkus/runtime/pom.xml index ce48c86327e..4fd86f78f01 100644 --- a/quarkus/runtime/pom.xml +++ b/quarkus/runtime/pom.xml @@ -80,8 +80,8 @@ quarkus-smallrye-metrics - io.quarkus - quarkus-infinispan-client + org.wildfly.security + wildfly-elytron io.quarkiverse.vault diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakClassLoader.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakClassLoader.java new file mode 100644 index 00000000000..507e7f6afa5 --- /dev/null +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakClassLoader.java @@ -0,0 +1,42 @@ +/* + * Copyright 2021 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * 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.keycloak.quarkus.runtime; + +import java.io.IOException; +import java.net.URL; +import java.sql.Driver; +import java.util.Collections; +import java.util.Enumeration; + +public class KeycloakClassLoader extends ClassLoader { + + KeycloakClassLoader() { + super(Thread.currentThread().getContextClassLoader()); + } + + @Override + public Enumeration getResources(String name) throws IOException { + // drivers are going to be loaded lazily, and we avoid loading all available drivers + // see https://github.com/quarkusio/quarkus/pull/7089 + if (name.contains(Driver.class.getName())) { + return Collections.emptyEnumeration(); + } + + return super.getResources(name); + } +} diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java index a0ff2e6b903..e286431ccd9 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java @@ -50,8 +50,6 @@ import io.quarkus.runtime.annotations.QuarkusMain; @ApplicationScoped public class KeycloakMain implements QuarkusApplication { - private static final Logger LOGGER = Logger.getLogger(KeycloakMain.class); - public static void main(String[] args) { System.setProperty("kc.version", Version.VERSION_KEYCLOAK); List cliArgs = Picocli.parseArgs(args); @@ -80,7 +78,11 @@ public class KeycloakMain implements QuarkusApplication { } public static void start(ExecutionExceptionHandler errorHandler, PrintWriter errStream) { + ClassLoader originalCl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(new KeycloakClassLoader()); + Quarkus.run(KeycloakMain.class, (exitCode, cause) -> { if (cause != null) { errorHandler.error(errStream, @@ -98,6 +100,8 @@ public class KeycloakMain implements QuarkusApplication { errorHandler.error(errStream, String.format("Unexpected error when starting the server in (%s) mode", getKeycloakModeFromProfile(getProfileOrDefault("prod"))), cause.getCause()); + } finally { + Thread.currentThread().setContextClassLoader(originalCl); } } @@ -107,7 +111,7 @@ public class KeycloakMain implements QuarkusApplication { @Override public int run(String... args) throws Exception { if (isDevProfile()) { - LOGGER.warnf("Running the server in development mode. DO NOT use this configuration in production."); + Logger.getLogger(KeycloakMain.class).warnf("Running the server in development mode. DO NOT use this configuration in production."); } int exitCode = ApplicationLifecycleManager.getExitCode(); diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java index 65b0ea138c1..c9bc8dd017f 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java @@ -62,17 +62,7 @@ public class KeycloakRecorder { public RuntimeValue createCacheInitializer(String config, ShutdownContext shutdownContext) { try { - ConfigurationBuilderHolder builder = new ParserRegistry().parse(config); - - if (builder.getNamedConfigurationBuilders().get("sessions").clustering().cacheMode().isClustered()) { - configureTransportStack(builder); - } - - // For Infinispan 10, we go with the JBoss marshalling. - // TODO: This should be replaced later with the marshalling recommended by infinispan. Probably protostream. - // See https://infinispan.org/docs/stable/titles/developing/developing.html#marshalling for the details - builder.getGlobalConfigurationBuilder().serialization().marshaller(new JBossUserMarshaller()); - CacheManagerFactory cacheManagerFactory = new CacheManagerFactory(builder); + CacheManagerFactory cacheManagerFactory = new CacheManagerFactory(config); shutdownContext.addShutdownTask(new Runnable() { @Override @@ -91,15 +81,6 @@ public class KeycloakRecorder { } } - private void configureTransportStack(ConfigurationBuilderHolder builder) { - String transportStack = Configuration.getRawValue("kc.cache-stack"); - - if (transportStack != null) { - builder.getGlobalConfigurationBuilder().transport().defaultTransport() - .addProperty("configurationFile", "default-configs/default-jgroups-" + transportStack + ".xml"); - } - } - public void registerShutdownHook(ShutdownContext shutdownContext) { shutdownContext.addShutdownTask(new Runnable() { @Override diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/database/jpa/QuarkusJpaConnectionProviderFactory.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/database/jpa/QuarkusJpaConnectionProviderFactory.java index 8a082b07b26..32115025ced 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/database/jpa/QuarkusJpaConnectionProviderFactory.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/database/jpa/QuarkusJpaConnectionProviderFactory.java @@ -122,9 +122,11 @@ public final class QuarkusJpaConnectionProviderFactory implements JpaConnectionP try { Map unitProperties = emf.getProperties(); - unitProperties.entrySet().stream() - .filter(entry -> entry.getKey().startsWith(QUERY_PROPERTY_PREFIX)) - .forEach(entry -> configureNamedQuery(entry.getKey().substring(QUERY_PROPERTY_PREFIX.length()), entry.getValue().toString(), em)); + for (Map.Entry entry : unitProperties.entrySet()) { + if (entry.getKey().startsWith(QUERY_PROPERTY_PREFIX)) { + configureNamedQuery(entry.getKey().substring(QUERY_PROPERTY_PREFIX.length()), entry.getValue().toString(), em); + } + } } finally { JpaUtils.closeEntityManager(em); } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/infinispan/CacheManagerFactory.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/infinispan/CacheManagerFactory.java index 51aa1f2e9bc..5f977b3f821 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/infinispan/CacheManagerFactory.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/infinispan/CacheManagerFactory.java @@ -23,18 +23,21 @@ import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import org.infinispan.configuration.parsing.ConfigurationBuilderHolder; +import org.infinispan.configuration.parsing.ParserRegistry; +import org.infinispan.jboss.marshalling.core.JBossUserMarshaller; import org.infinispan.manager.DefaultCacheManager; import org.jboss.logging.Logger; +import org.keycloak.quarkus.runtime.configuration.Configuration; public class CacheManagerFactory { - private ConfigurationBuilderHolder config; + private String config; private DefaultCacheManager cacheManager; private Future cacheManagerFuture; private ExecutorService executor; private boolean initialized; - public CacheManagerFactory(ConfigurationBuilderHolder config) { + public CacheManagerFactory(String config) { this.config = config; this.executor = createThreadPool(); this.cacheManagerFuture = executor.submit(this::startCacheManager); @@ -69,7 +72,18 @@ public class CacheManagerFactory { } private DefaultCacheManager startCacheManager() { - return new DefaultCacheManager(config, isStartEagerly()); + ConfigurationBuilderHolder builder = new ParserRegistry().parse(config); + + if (builder.getNamedConfigurationBuilders().get("sessions").clustering().cacheMode().isClustered()) { + configureTransportStack(builder); + } + + // For Infinispan 10, we go with the JBoss marshalling. + // TODO: This should be replaced later with the marshalling recommended by infinispan. Probably protostream. + // See https://infinispan.org/docs/stable/titles/developing/developing.html#marshalling for the details + builder.getGlobalConfigurationBuilder().serialization().marshaller(new JBossUserMarshaller()); + + return new DefaultCacheManager(builder, isStartEagerly()); } private boolean isStartEagerly() { @@ -101,4 +115,13 @@ public class CacheManagerFactory { } } } + + private void configureTransportStack(ConfigurationBuilderHolder builder) { + String transportStack = Configuration.getRawValue("kc.cache-stack"); + + if (transportStack != null) { + builder.getGlobalConfigurationBuilder().transport().defaultTransport() + .addProperty("configurationFile", "default-configs/default-jgroups-" + transportStack + ".xml"); + } + } } diff --git a/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProviderFactory.java b/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProviderFactory.java index ba13af21377..2f31c7171c4 100644 --- a/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProviderFactory.java +++ b/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProviderFactory.java @@ -16,23 +16,30 @@ package org.keycloak.credential; +import org.keycloak.Config; import org.keycloak.common.Profile; import org.keycloak.models.KeycloakSession; import com.webauthn4j.converter.util.ObjectConverter; +import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.provider.EnvironmentDependentProviderFactory; public class WebAuthnCredentialProviderFactory implements CredentialProviderFactory, EnvironmentDependentProviderFactory { public static final String PROVIDER_ID = "keycloak-webauthn"; - private static ObjectConverter converter = new ObjectConverter(); + private ObjectConverter converter; @Override public CredentialProvider create(KeycloakSession session) { return new WebAuthnCredentialProvider(session, converter); } + @Override + public void init(Config.Scope config) { + converter = new ObjectConverter(); + } + @Override public String getId() { return PROVIDER_ID;