keycloak-aplcache

Merge pull request #793 from mposolda/dynamic-adapter-registration Rewrite

10/22/2014 1:52:19 PM

Details

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 6fab4cf..5365620 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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -15,66 +18,47 @@ public class NodesRegistrationManagement {
 
     private static final Logger log = Logger.getLogger(NodesRegistrationManagement.class);
 
-    private final KeycloakDeployment deployment;
-    private final Timer timer;
-
-    // True if at least one event was successfully sent
-    private volatile boolean registered = false;
-
-    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);
-                }
+    private final Map<String, NodeRegistrationContext> nodeRegistrations = new ConcurrentHashMap<String, NodeRegistrationContext>();
+    private final Executor executor = Executors.newSingleThreadExecutor();
+
+    // 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() {
+
+                    @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);
             }
         }
     }
 
-    public void stop() {
-        removePeriodicListener();
-        if (registered) {
-            sendUnregistrationEvent();
+    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;
         }
-    }
-
-    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);
+        return currentRegistration.lastRegistrationTime + resolvedDeployment.getRegisterNodePeriod() < Time.currentTime();
     }
 
-    protected void removePeriodicListener() {
-        timer.cancel();
+    /**
+     * Called during undeployment or server stop. De-register from all previously registered deployments
+     */
+    public void stop() {
+        Collection<NodeRegistrationContext> allRegistrations = nodeRegistrations.values();
+        for (NodeRegistrationContext registration : allRegistrations) {
+            sendUnregistrationEvent(registration.resolvedDeployment);
+        }
     }
 
     protected void sendRegistrationEvent(KeycloakDeployment deployment) {
@@ -83,8 +67,9 @@ public class NodesRegistrationManagement {
         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 a7a66cf..8b40abb 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 9465692..94447a1 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 24d476b..5c7a16b 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 3debc14..d6ca115 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