KEYCLOAK-12175 - Platform SPI
This commit is contained in:
parent
30e024a3c9
commit
e2144d6aec
16 changed files with 258 additions and 80 deletions
|
@ -44,7 +44,7 @@
|
||||||
</context-param>
|
</context-param>
|
||||||
|
|
||||||
<listener>
|
<listener>
|
||||||
<listener-class>org.keycloak.services.listeners.KeycloakSessionDestroyListener</listener-class>
|
<listener-class>org.keycloak.provider.wildfly.WildflyLifecycleListener</listener-class>
|
||||||
</listener>
|
</listener>
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
<module name="org.keycloak.keycloak-saml-core-public" services="import"/>
|
<module name="org.keycloak.keycloak-saml-core-public" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-saml-core" services="import"/>
|
<module name="org.keycloak.keycloak-saml-core" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-services" export="true" services="import"/>
|
<module name="org.keycloak.keycloak-services" export="true" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-wildfly-extensions" services="import"/>
|
<module name="org.keycloak.keycloak-wildfly-extensions" export="true" services="import"/>
|
||||||
|
|
||||||
<!-- Authorization -->
|
<!-- Authorization -->
|
||||||
<module name="org.keycloak.keycloak-authz-policy-common" services="import"/>
|
<module name="org.keycloak.keycloak-authz-policy-common" services="import"/>
|
||||||
|
|
|
@ -17,23 +17,31 @@
|
||||||
|
|
||||||
package org.keycloak.provider.quarkus;
|
package org.keycloak.provider.quarkus;
|
||||||
|
|
||||||
|
import io.quarkus.runtime.ShutdownEvent;
|
||||||
import io.quarkus.runtime.StartupEvent;
|
import io.quarkus.runtime.StartupEvent;
|
||||||
import javax.enterprise.context.ApplicationScoped;
|
import javax.enterprise.context.ApplicationScoped;
|
||||||
import javax.enterprise.event.Observes;
|
import javax.enterprise.event.Observes;
|
||||||
|
import org.keycloak.platform.Platform;
|
||||||
|
|
||||||
@ApplicationScoped
|
@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) {
|
private void onShutdownEvent(@Observes ShutdownEvent event) {
|
||||||
if (command != null) {
|
|
||||||
command.run();
|
Runnable shutdownHook = ((QuarkusPlatform) Platform.getPlatform()).shutdownHook;
|
||||||
}
|
|
||||||
|
if (shutdownHook != null)
|
||||||
|
shutdownHook.run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
|
@ -42,10 +42,6 @@
|
||||||
<param-name>resteasy.disable.html.sanitizer</param-name>
|
<param-name>resteasy.disable.html.sanitizer</param-name>
|
||||||
<param-value>true</param-value>
|
<param-value>true</param-value>
|
||||||
</context-param>
|
</context-param>
|
||||||
<context-param>
|
|
||||||
<param-name>keycloak.embedded</param-name>
|
|
||||||
<param-value>true</param-value>
|
|
||||||
</context-param>
|
|
||||||
|
|
||||||
<listener>
|
<listener>
|
||||||
<listener-class>
|
<listener-class>
|
||||||
|
@ -53,10 +49,6 @@
|
||||||
</listener-class>
|
</listener-class>
|
||||||
</listener>
|
</listener>
|
||||||
|
|
||||||
<listener>
|
|
||||||
<listener-class>org.keycloak.services.listeners.KeycloakSessionDestroyListener</listener-class>
|
|
||||||
</listener>
|
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
<filter-name>Keycloak Session Management</filter-name>
|
<filter-name>Keycloak Session Management</filter-name>
|
||||||
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
|
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
|
||||||
|
|
42
services/src/main/java/org/keycloak/platform/Platform.java
Normal file
42
services/src/main/java/org/keycloak/platform/Platform.java
Normal file
|
@ -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<PlatformProvider> loader = ServiceLoader.load(PlatformProvider.class, Platform.class.getClassLoader());
|
||||||
|
try {
|
||||||
|
INSTANCE = loader.iterator().next();
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
throw new RuntimeException("No PlatformProvider found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return INSTANCE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -35,6 +35,8 @@ import org.keycloak.models.dblock.DBLockProvider;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.PostMigrationEvent;
|
import org.keycloak.models.utils.PostMigrationEvent;
|
||||||
import org.keycloak.models.utils.RepresentationToModel;
|
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.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||||
|
@ -65,13 +67,11 @@ import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,13 +80,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
*/
|
*/
|
||||||
public class KeycloakApplication extends Application {
|
public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
public static final String KEYCLOAK_EMBEDDED = "keycloak.embedded";
|
|
||||||
|
|
||||||
public static final AtomicBoolean BOOTSTRAP_ADMIN_USER = new AtomicBoolean(false);
|
public static final AtomicBoolean BOOTSTRAP_ADMIN_USER = new AtomicBoolean(false);
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(KeycloakApplication.class);
|
private static final Logger logger = Logger.getLogger(KeycloakApplication.class);
|
||||||
|
|
||||||
protected boolean embedded = false;
|
protected final PlatformProvider platform = Platform.getPlatform();
|
||||||
|
|
||||||
protected Set<Object> singletons = new HashSet<Object>();
|
protected Set<Object> singletons = new HashSet<Object>();
|
||||||
protected Set<Class<?>> classes = new HashSet<Class<?>>();
|
protected Set<Class<?>> classes = new HashSet<Class<?>>();
|
||||||
|
@ -97,14 +95,11 @@ public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
logger.debugv("PlatformProvider: {0}", platform.getClass().getName());
|
||||||
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
|
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
|
||||||
|
|
||||||
ServletContext context = Resteasy.getContextData(ServletContext.class);
|
ServletContext context = Resteasy.getContextData(ServletContext.class);
|
||||||
|
|
||||||
if ("true".equals(context.getInitParameter(KEYCLOAK_EMBEDDED))) {
|
|
||||||
embedded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
this.sessionFactory = createSessionFactory();
|
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 ObjectMapperResolver(Boolean.parseBoolean(System.getProperty("keycloak.jsonPrettyPrint", "false"))));
|
||||||
singletons.add(new WelcomeResource());
|
singletons.add(new WelcomeResource());
|
||||||
|
|
||||||
init(this::startup);
|
platform.onStartup(this::startup);
|
||||||
|
platform.onShutdown(this::shutdown);
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!embedded) {
|
platform.exit(t);
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
throw t;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(Runnable function) {
|
|
||||||
|
|
||||||
ServiceLoader<Startup> loader = ServiceLoader.load(Startup.class);
|
|
||||||
Iterator<Startup> iterator = loader.iterator();
|
|
||||||
|
|
||||||
if (iterator.hasNext()) {
|
|
||||||
iterator.next().execute(function);
|
|
||||||
} else {
|
|
||||||
function.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
// Migrate model, bootstrap master realm, import realms and create admin user. This is done with acquired dbLock
|
||||||
protected ExportImportManager migrateAndBootstrap() {
|
protected ExportImportManager migrateAndBootstrap() {
|
||||||
ExportImportManager exportImportManager;
|
ExportImportManager exportImportManager;
|
||||||
|
@ -270,7 +255,7 @@ public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ConfigProviderFactory factory = loader.iterator().next();
|
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")));
|
Config.init(factory.create().orElseThrow(() -> new RuntimeException("Failed to load Keycloak configuration")));
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
throw new RuntimeException("No valid ConfigProvider found");
|
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 {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,6 @@ public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUnderto
|
||||||
di.setClassLoader(getClass().getClassLoader());
|
di.setClassLoader(getClass().getClassLoader());
|
||||||
di.setContextPath("/auth");
|
di.setContextPath("/auth");
|
||||||
di.setDeploymentName("Keycloak");
|
di.setDeploymentName("Keycloak");
|
||||||
di.addInitParameter(KeycloakApplication.KEYCLOAK_EMBEDDED, "true");
|
|
||||||
if (configuration.getKeycloakConfigPropertyOverridesMap() != null) {
|
if (configuration.getKeycloakConfigPropertyOverridesMap() != null) {
|
||||||
try {
|
try {
|
||||||
di.addInitParameter(JsonConfigProviderFactory.SERVER_CONTEXT_CONFIG_PROPERTY_OVERRIDES,
|
di.addInitParameter(JsonConfigProviderFactory.SERVER_CONTEXT_CONFIG_PROPERTY_OVERRIDES,
|
||||||
|
|
|
@ -399,8 +399,6 @@ public class KeycloakServer {
|
||||||
di.setDeploymentName("Keycloak");
|
di.setDeploymentName("Keycloak");
|
||||||
di.setDefaultEncoding("UTF-8");
|
di.setDefaultEncoding("UTF-8");
|
||||||
|
|
||||||
di.addInitParameter(KeycloakApplication.KEYCLOAK_EMBEDDED, "true");
|
|
||||||
|
|
||||||
di.setDefaultServletConfig(new DefaultServletConfig(true));
|
di.setDefaultServletConfig(new DefaultServletConfig(true));
|
||||||
|
|
||||||
ServletInfo restEasyDispatcher = Servlets.servlet("Keycloak REST Interface", HttpServlet30Dispatcher.class);
|
ServletInfo restEasyDispatcher = Servlets.servlet("Keycloak REST Interface", HttpServlet30Dispatcher.class);
|
||||||
|
|
|
@ -15,17 +15,24 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.provider.quarkus;
|
package org.keycloak.testsuite;
|
||||||
|
|
||||||
import io.quarkus.arc.Arc;
|
import org.keycloak.platform.PlatformProvider;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
|
||||||
|
|
||||||
public class QuarkusStartup implements KeycloakApplication.Startup {
|
public class TestPlatform implements PlatformProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(Runnable command) {
|
public void onStartup(Runnable startupHook) {
|
||||||
QuarkusStartupObserver observer = Arc.container().instance(QuarkusStartupObserver.class).get();
|
startupHook.run();
|
||||||
observer.setCommand(command);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onShutdown(Runnable shutdownHook) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exit(Throwable cause) {
|
||||||
|
throw new RuntimeException(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -15,4 +15,4 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
org.keycloak.provider.quarkus.QuarkusStartup
|
org.keycloak.testsuite.TestPlatform
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -15,17 +15,15 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.listeners;
|
package org.keycloak.provider.wildfly;
|
||||||
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
|
import javax.servlet.annotation.WebListener;
|
||||||
|
import org.keycloak.platform.Platform;
|
||||||
|
|
||||||
/**
|
@WebListener
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
public class WildflyLifecycleListener implements ServletContextListener {
|
||||||
*/
|
|
||||||
public class KeycloakSessionDestroyListener implements ServletContextListener {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
|
@ -33,10 +31,13 @@ public class KeycloakSessionDestroyListener implements ServletContextListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextDestroyed(ServletContextEvent sce) {
|
public void contextDestroyed(ServletContextEvent sce) {
|
||||||
KeycloakSessionFactory sessionFactory = (KeycloakSessionFactory) sce.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
|
|
||||||
if (sessionFactory != null) {
|
Runnable shutdownHook = ((WildflyPlatform) Platform.getPlatform()).shutdownHook;
|
||||||
sessionFactory.close();
|
|
||||||
|
if (shutdownHook != null) {
|
||||||
|
shutdownHook.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in a new issue