diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml index fc904903a8..df80df8811 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml @@ -44,7 +44,7 @@ - org.keycloak.services.listeners.KeycloakSessionDestroyListener + org.keycloak.provider.wildfly.WildflyLifecycleListener diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml index 210d9ac70c..30c0fdf101 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml @@ -38,7 +38,7 @@ - + diff --git a/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusStartupObserver.java b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java similarity index 61% rename from quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusStartupObserver.java rename to quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java index 318be34109..c2c9ef2653 100644 --- a/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusStartupObserver.java +++ b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java @@ -17,23 +17,31 @@ package org.keycloak.provider.quarkus; +import io.quarkus.runtime.ShutdownEvent; import io.quarkus.runtime.StartupEvent; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; +import org.keycloak.platform.Platform; @ApplicationScoped -public class QuarkusStartupObserver { +public class QuarkusLifecycleObserver { - private Runnable command; + private void onStartupEvent(@Observes StartupEvent event) { + + Runnable startupHook = ((QuarkusPlatform) Platform.getPlatform()).startupHook; + + if (startupHook != null) + startupHook.run(); - public void setCommand(Runnable command) { - this.command = command; } - private void startupEvent(@Observes StartupEvent event) { - if (command != null) { - command.run(); - } + private void onShutdownEvent(@Observes ShutdownEvent event) { + + Runnable shutdownHook = ((QuarkusPlatform) Platform.getPlatform()).shutdownHook; + + if (shutdownHook != null) + shutdownHook.run(); + } } diff --git a/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusPlatform.java b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusPlatform.java new file mode 100644 index 0000000000..c11490bb56 --- /dev/null +++ b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusPlatform.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019 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.provider.quarkus; + +import org.keycloak.platform.PlatformProvider; + +public class QuarkusPlatform implements PlatformProvider { + + Runnable startupHook; + Runnable shutdownHook; + + @Override + public void onStartup(Runnable startupHook) { + this.startupHook = startupHook; + } + + @Override + public void onShutdown(Runnable shutdownHook) { + this.shutdownHook = shutdownHook; + } + + @Override + public void exit(Throwable cause) { + throw new RuntimeException(cause); + } + +} diff --git a/quarkus/extensions/src/main/resources/META-INF/services/org.keycloak.platform.PlatformProvider b/quarkus/extensions/src/main/resources/META-INF/services/org.keycloak.platform.PlatformProvider new file mode 100644 index 0000000000..cb5b719bdc --- /dev/null +++ b/quarkus/extensions/src/main/resources/META-INF/services/org.keycloak.platform.PlatformProvider @@ -0,0 +1,18 @@ +# +# Copyright 2019 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. +# + +org.keycloak.provider.quarkus.QuarkusPlatform diff --git a/quarkus/server/src/main/resources/META-INF/web.xml b/quarkus/server/src/main/resources/META-INF/web.xml index 09fe42b57b..2f28c8139b 100644 --- a/quarkus/server/src/main/resources/META-INF/web.xml +++ b/quarkus/server/src/main/resources/META-INF/web.xml @@ -42,10 +42,6 @@ resteasy.disable.html.sanitizer true - - keycloak.embedded - true - @@ -53,10 +49,6 @@ - - org.keycloak.services.listeners.KeycloakSessionDestroyListener - - Keycloak Session Management org.keycloak.services.filters.KeycloakSessionServletFilter diff --git a/services/src/main/java/org/keycloak/platform/Platform.java b/services/src/main/java/org/keycloak/platform/Platform.java new file mode 100644 index 0000000000..ba7cce19f8 --- /dev/null +++ b/services/src/main/java/org/keycloak/platform/Platform.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019 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.platform; + +import java.util.NoSuchElementException; +import java.util.ServiceLoader; + +public class Platform { + + private static PlatformProvider INSTANCE; + + public static PlatformProvider getPlatform() { + + if (INSTANCE == null) { + ServiceLoader loader = ServiceLoader.load(PlatformProvider.class, Platform.class.getClassLoader()); + try { + INSTANCE = loader.iterator().next(); + } catch (NoSuchElementException e) { + throw new RuntimeException("No PlatformProvider found"); + } + } + + return INSTANCE; + + } + +} diff --git a/services/src/main/java/org/keycloak/platform/PlatformProvider.java b/services/src/main/java/org/keycloak/platform/PlatformProvider.java new file mode 100644 index 0000000000..428eb1e0a3 --- /dev/null +++ b/services/src/main/java/org/keycloak/platform/PlatformProvider.java @@ -0,0 +1,28 @@ +/* + * Copyright 2019 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.platform; + +public interface PlatformProvider { + + void onStartup(Runnable runnable); + + void onShutdown(Runnable runnable); + + void exit(Throwable cause); + +} diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java index 646cd53b1a..735f7e26ac 100644 --- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java +++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java @@ -35,6 +35,8 @@ import org.keycloak.models.dblock.DBLockProvider; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.PostMigrationEvent; import org.keycloak.models.utils.RepresentationToModel; +import org.keycloak.platform.Platform; +import org.keycloak.platform.PlatformProvider; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.services.DefaultKeycloakSessionFactory; @@ -65,13 +67,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.ServiceLoader; import java.util.Set; import java.util.StringTokenizer; -import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -80,13 +80,11 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class KeycloakApplication extends Application { - public static final String KEYCLOAK_EMBEDDED = "keycloak.embedded"; - public static final AtomicBoolean BOOTSTRAP_ADMIN_USER = new AtomicBoolean(false); private static final Logger logger = Logger.getLogger(KeycloakApplication.class); - protected boolean embedded = false; + protected final PlatformProvider platform = Platform.getPlatform(); protected Set singletons = new HashSet(); protected Set> classes = new HashSet>(); @@ -97,14 +95,11 @@ public class KeycloakApplication extends Application { try { + logger.debugv("PlatformProvider: {0}", platform.getClass().getName()); logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName()); ServletContext context = Resteasy.getContextData(ServletContext.class); - if ("true".equals(context.getInitParameter(KEYCLOAK_EMBEDDED))) { - embedded = true; - } - loadConfig(); this.sessionFactory = createSessionFactory(); @@ -125,26 +120,11 @@ public class KeycloakApplication extends Application { singletons.add(new ObjectMapperResolver(Boolean.parseBoolean(System.getProperty("keycloak.jsonPrettyPrint", "false")))); singletons.add(new WelcomeResource()); - init(this::startup); + platform.onStartup(this::startup); + platform.onShutdown(this::shutdown); } catch (Throwable t) { - if (!embedded) { - exit(1); - } - throw t; - } - - } - - private void init(Runnable function) { - - ServiceLoader loader = ServiceLoader.load(Startup.class); - Iterator iterator = loader.iterator(); - - if (iterator.hasNext()) { - iterator.next().execute(function); - } else { - function.run(); + platform.exit(t); } } @@ -191,6 +171,11 @@ public class KeycloakApplication extends Application { } + protected void shutdown() { + if (sessionFactory != null) + sessionFactory.close(); + } + // Migrate model, bootstrap master realm, import realms and create admin user. This is done with acquired dbLock protected ExportImportManager migrateAndBootstrap() { ExportImportManager exportImportManager; @@ -270,7 +255,7 @@ public class KeycloakApplication extends Application { try { ConfigProviderFactory factory = loader.iterator().next(); - logger.infov("Using ConfigProvider: {0}", factory.getClass().getName()); + logger.debugv("ConfigProvider: {0}", factory.getClass().getName()); Config.init(factory.create().orElseThrow(() -> new RuntimeException("Failed to load Keycloak configuration"))); } catch (NoSuchElementException e) { throw new RuntimeException("No valid ConfigProvider found"); @@ -432,16 +417,4 @@ public class KeycloakApplication extends Application { } } - private void exit(int status) { - new Thread() { - @Override - public void run() { - System.exit(status); - } - }.start(); - } - - public static interface Startup extends Executor { - } - } diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java index 300673252b..c94d048f54 100644 --- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java +++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java @@ -88,7 +88,6 @@ public class KeycloakOnUndertow implements DeployableContainerStian Thorgersen - */ -public class KeycloakSessionDestroyListener implements ServletContextListener { +@WebListener +public class WildflyLifecycleListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { @@ -33,10 +31,13 @@ public class KeycloakSessionDestroyListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent sce) { - KeycloakSessionFactory sessionFactory = (KeycloakSessionFactory) sce.getServletContext().getAttribute(KeycloakSessionFactory.class.getName()); - if (sessionFactory != null) { - sessionFactory.close(); + + Runnable shutdownHook = ((WildflyPlatform) Platform.getPlatform()).shutdownHook; + + if (shutdownHook != null) { + shutdownHook.run(); } + } } diff --git a/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/WildflyPlatform.java b/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/WildflyPlatform.java new file mode 100644 index 0000000000..103e318076 --- /dev/null +++ b/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/WildflyPlatform.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019 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.provider.wildfly; + +import org.keycloak.platform.PlatformProvider; +import org.keycloak.services.ServicesLogger; + +public class WildflyPlatform implements PlatformProvider { + + Runnable shutdownHook; + + @Override + public void onStartup(Runnable startupHook) { + startupHook.run(); + } + + @Override + public void onShutdown(Runnable shutdownHook) { + this.shutdownHook = shutdownHook; + } + + @Override + public void exit(Throwable cause) { + ServicesLogger.LOGGER.fatal(cause); + exit(1); + } + + private void exit(int status) { + new Thread() { + @Override + public void run() { + System.exit(status); + } + }.start(); + } + +} diff --git a/wildfly/extensions/src/main/resources/META-INF/services/org.keycloak.platform.PlatformProvider b/wildfly/extensions/src/main/resources/META-INF/services/org.keycloak.platform.PlatformProvider new file mode 100644 index 0000000000..606cc86c61 --- /dev/null +++ b/wildfly/extensions/src/main/resources/META-INF/services/org.keycloak.platform.PlatformProvider @@ -0,0 +1,18 @@ +# +# Copyright 2019 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. +# + +org.keycloak.provider.wildfly.WildflyPlatform