diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java
index 6fab4cf12f..5365620d8b 100644
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java
@@ -1,12 +1,15 @@
package org.keycloak.adapters;
import java.io.IOException;
-import java.util.Timer;
-import java.util.TimerTask;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import org.jboss.logging.Logger;
-import org.keycloak.enums.RelativeUrlsUsed;
import org.keycloak.util.HostUtils;
+import org.keycloak.util.Time;
/**
* @author Marek Posolda
@@ -15,76 +18,58 @@ public class NodesRegistrationManagement {
private static final Logger log = Logger.getLogger(NodesRegistrationManagement.class);
- private final KeycloakDeployment deployment;
- private final Timer timer;
+ private final Map nodeRegistrations = new ConcurrentHashMap();
+ private final Executor executor = Executors.newSingleThreadExecutor();
- // True if at least one event was successfully sent
- private volatile boolean registered = false;
+ // Sending registration event during first request to application or if re-registration is needed
+ public void tryRegister(final KeycloakDeployment resolvedDeployment) {
+ if (resolvedDeployment.isRegisterNodeAtStartup()) {
+ final String registrationUri = resolvedDeployment.getRegisterNodeUrl();
+ if (needRefreshRegistration(registrationUri, resolvedDeployment)) {
+ Runnable runnable = new Runnable() {
- public NodesRegistrationManagement(KeycloakDeployment deployment) {
- this.deployment = deployment;
- this.timer = new Timer();
- }
-
- // Register listener for periodic sending of re-registration event
- public void start() {
- if (deployment.getRegisterNodePeriod() <= 0) {
- log.infof("Skip periodic registration of cluster nodes at startup for application %s", deployment.getResourceName());
- return;
- }
-
- if (deployment.getRelativeUrls() == null || deployment.getRelativeUrls() == RelativeUrlsUsed.ALL_REQUESTS) {
- log.errorf("Skip periodic registration of cluster nodes at startup for application %s as Keycloak node can't be contacted. Make sure to provide some non-relative URI in adapters configuration.", deployment.getResourceName());
- return;
- }
-
- addPeriodicListener();
- }
-
- // Sending registration event during first request to application
- public void tryRegister(KeycloakDeployment resolvedDeployment) {
- if (resolvedDeployment.isRegisterNodeAtStartup() && !registered) {
- synchronized (this) {
- if (!registered) {
- sendRegistrationEvent(resolvedDeployment);
- }
+ @Override
+ public void run() {
+ // Need to check it again in case that executor triggered by other thread already finished computation in the meantime
+ if (needRefreshRegistration(registrationUri, resolvedDeployment)) {
+ sendRegistrationEvent(resolvedDeployment);
+ }
+ }
+ };
+ executor.execute(runnable);
}
}
}
+ private boolean needRefreshRegistration(String registrationUri, KeycloakDeployment resolvedDeployment) {
+ NodeRegistrationContext currentRegistration = nodeRegistrations.get(registrationUri);
+ /// We don't yet have any registration for this node
+ if (currentRegistration == null) {
+ return true;
+ }
+
+ return currentRegistration.lastRegistrationTime + resolvedDeployment.getRegisterNodePeriod() < Time.currentTime();
+ }
+
+ /**
+ * Called during undeployment or server stop. De-register from all previously registered deployments
+ */
public void stop() {
- removePeriodicListener();
- if (registered) {
- sendUnregistrationEvent();
+ Collection allRegistrations = nodeRegistrations.values();
+ for (NodeRegistrationContext registration : allRegistrations) {
+ sendUnregistrationEvent(registration.resolvedDeployment);
}
}
- protected void addPeriodicListener() {
- TimerTask task = new TimerTask() {
-
- @Override
- public void run() {
- sendRegistrationEvent(deployment);
- }
- };
-
- long interval = deployment.getRegisterNodePeriod() * 1000;
- log.info("Setup of periodic re-registration event sending each " + interval + " ms");
- timer.schedule(task, interval, interval);
- }
-
- protected void removePeriodicListener() {
- timer.cancel();
- }
-
protected void sendRegistrationEvent(KeycloakDeployment deployment) {
log.info("Sending registration event right now");
String host = HostUtils.getIpAddress();
try {
ServerRequest.invokeRegisterNode(deployment, host);
+ NodeRegistrationContext regContext = new NodeRegistrationContext(Time.currentTime(), deployment);
+ nodeRegistrations.put(deployment.getRegisterNodeUrl(), regContext);
log.infof("Node '%s' successfully registered in Keycloak", host);
- registered = true;
} catch (ServerRequest.HttpFailure failure) {
log.error("failed to register node to keycloak");
log.error("status from server: " + failure.getStatus());
@@ -96,7 +81,7 @@ public class NodesRegistrationManagement {
}
}
- protected boolean sendUnregistrationEvent() {
+ protected boolean sendUnregistrationEvent(KeycloakDeployment deployment) {
log.info("Sending Unregistration event right now");
String host = HostUtils.getIpAddress();
@@ -117,4 +102,16 @@ public class NodesRegistrationManagement {
}
}
+ public static class NodeRegistrationContext {
+
+ private final Integer lastRegistrationTime;
+ // deployment instance used for registration request
+ private final KeycloakDeployment resolvedDeployment;
+
+ public NodeRegistrationContext(Integer lastRegTime, KeycloakDeployment deployment) {
+ this.lastRegistrationTime = lastRegTime;
+ this.resolvedDeployment = deployment;
+ }
+ }
+
}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
index a7a66cf8f5..8b40abb567 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
@@ -127,8 +127,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getController());
setNext(actions);
- nodesRegistrationManagement = new NodesRegistrationManagement(kd);
- nodesRegistrationManagement.start();
+ nodesRegistrationManagement = new NodesRegistrationManagement();
}
protected void beforeStop() {
diff --git a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
index 9465692c1f..94447a1a59 100755
--- a/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
+++ b/integration/tomcat7/adapter/src/main/java/org/keycloak/adapters/tomcat7/KeycloakAuthenticatorValve.java
@@ -105,8 +105,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getObjectName());
setNext(actions);
- nodesRegistrationManagement = new NodesRegistrationManagement(kd);
- nodesRegistrationManagement.start();
+ nodesRegistrationManagement = new NodesRegistrationManagement();
}
protected void beforeStop() {
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
index 24d476b957..5c7a16b4bd 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
@@ -112,7 +112,7 @@ public class KeycloakServletExtension implements ServletExtension {
AdapterDeploymentContext deploymentContext = new AdapterDeploymentContext(deployment);
servletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement();
- final NodesRegistrationManagement nodesRegistrationManagement = new NodesRegistrationManagement(deployment);
+ final NodesRegistrationManagement nodesRegistrationManagement = new NodesRegistrationManagement();
final ServletKeycloakAuthMech mech = createAuthenticationMechanism(deploymentInfo, deploymentContext, userSessionManagement, nodesRegistrationManagement);
UndertowAuthenticatedActionsHandler.Wrapper actions = new UndertowAuthenticatedActionsHandler.Wrapper(deploymentContext);
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationManagementWrapper.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationManagementWrapper.java
index 3debc14071..d6ca115880 100644
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationManagementWrapper.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowNodesRegistrationManagementWrapper.java
@@ -18,7 +18,6 @@ public class UndertowNodesRegistrationManagementWrapper implements ServletContex
@Override
public void contextInitialized(ServletContextEvent sce) {
- delegate.start();
}
@Override