+ * Exception message will be "Object cannot be 'null'"
+ *
+ * @param obj The object to check
+ * @param clazz The class of the object
+ * @param The type of the object
+ * @return The object if it is not null
+ */
public static T nonNull(T obj, Class> clazz) {
return nonNull(obj, clazz.getSimpleName());
}
+ /**
+ * Check if the object is not null and throw a {@link NullPointerException} if it is.
+ *
+ * @param obj The object to check
+ * @param message The message to throw with the exception
+ * @param The type of the object
+ * @return The object if it is not null
+ */
public static T nonNull(T obj, String message) {
if (obj == null) {
throw new NullPointerException(message);
}
return obj;
}
+
+ /**
+ * Check if the object is not null and throw a {@link NullPointerException} if it is.
+ *
+ * Exception message will be "Object cannot be 'null'"
+ *
+ * @param obj The object to check
+ * @param object The name of the object
+ * @param The type of the object
+ * @return The object if it is not null
+ * @throws NullPointerException If the object is null
+ */
+ public static T nonNullObject(T obj, String object) {
+ if (obj == null) {
+ throw new NullPointerException(object + " cannot be 'null'");
+ }
+ return obj;
+ }
}
diff --git a/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/GlobalExecutors.java b/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/GlobalExecutors.java
index e82a93311..c7082f607 100644
--- a/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/GlobalExecutors.java
+++ b/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/GlobalExecutors.java
@@ -54,10 +54,10 @@ private GlobalExecutors() {
}
/**
- * Submit a new {@link Runnable} task to executed
+ * Submit a new {@link Runnable} task to execute
*
* @param runnable {@link Runnable} to be executed
- * @return {@link CompletableFuture} Instance of task to be executed
+ * @return {@link CompletableFuture} Instance of a task to be executed
*/
public static CompletableFuture submitTask(Runnable runnable) {
return CompletableFuture.runAsync(runnable, EXECUTOR_SERVICE);
@@ -66,9 +66,9 @@ public static CompletableFuture submitTask(Runnable runnable) {
/**
* Submit a new task to be executed
*
- * @param supplier {@link Supplier} implementing task to be executed
+ * @param supplier {@link Supplier} implementing a task to be executed
* @param Class implementing {@link Supplier}
- * @return {@link CompletableFuture} Instance of task to be executed
+ * @return {@link CompletableFuture} Instance of a task to be executed
*/
public static CompletableFuture submitTask(Supplier supplier) {
return CompletableFuture.supplyAsync(supplier, EXECUTOR_SERVICE);
@@ -78,7 +78,7 @@ public static CompletableFuture submitTask(Supplier supplier) {
* Submit and schedule a new {@link Runnable} task to be executed with a fixed delay
*
* @param runnable {@link Runnable} to be executed
- * @return {@link CompletableFuture} Instance of task to be executed
+ * @return {@link CompletableFuture} Instance of a task to be executed
*/
public static ScheduledFuture> submitTaskAndRunEvery(Runnable runnable, int initialDelay, int period, TimeUnit timeUnit) {
return SCHEDULED_EXECUTOR_SERVICE.scheduleWithFixedDelay(runnable, initialDelay, period, timeUnit);
diff --git a/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/DefaultEvent.java b/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/DefaultEvent.java
index 9de8441da..65a6ee1fc 100644
--- a/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/DefaultEvent.java
+++ b/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/DefaultEvent.java
@@ -20,7 +20,7 @@
import java.util.concurrent.CompletableFuture;
/**
- * Default implementation of {@link Event}
+ * Default implementation of an {@link Event}
*/
public class DefaultEvent implements Event {
@@ -30,8 +30,7 @@ public class DefaultEvent implements Event {
private Throwable throwable;
/**
- * Mark this event as successful with 'null' successful
- * completion object
+ * Mark this event as successful with 'null' successfulcompletion object
*/
public void markSuccess() {
markSuccess(null);
diff --git a/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/Event.java b/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/Event.java
index c74b05ed0..11a2181ff 100644
--- a/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/Event.java
+++ b/concurrent/src/main/java/com/shieldblaze/expressgateway/concurrent/event/Event.java
@@ -19,6 +19,11 @@
import java.util.concurrent.CompletableFuture;
+/**
+ * {@link Event} is an object which is created as a result of an operation.
+ *
+ * @param Type of the operation result
+ */
public interface Event {
/**
@@ -28,12 +33,17 @@ public interface Event {
/**
* Set to {@code true} if the event has finished else set to {@code false}.
+ *
+ * Note: This does not mean that the operation was successful. Use {@link #isSuccess()} to check that.
*/
boolean isFinished();
/**
* Set to {@code true} if the event has finished and operation was successful else
* set to {@code false}.
+ *
+ *
+ * {@link #isFinished()} will always return {@code true} if this method returns {@code true}.
*/
boolean isSuccess();
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/cluster/CoreContext.java b/core/src/main/java/com/shieldblaze/expressgateway/core/cluster/CoreContext.java
index 88f17960f..c920c8354 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/cluster/CoreContext.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/cluster/CoreContext.java
@@ -18,81 +18,92 @@
package com.shieldblaze.expressgateway.core.cluster;
import com.shieldblaze.expressgateway.backend.Node;
+import com.shieldblaze.expressgateway.core.exceptions.NotFoundException;
+import com.shieldblaze.expressgateway.core.loadbalancer.L4LoadBalancer;
import java.util.Map;
-import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+import static com.shieldblaze.expressgateway.common.utils.ObjectUtils.nonNullObject;
+
/**
- * This class holds all information about all load balancers.
+ * {@link CoreContext} holds all the {@link L4LoadBalancer} instances
*/
public final class CoreContext {
/**
- * Mapping of Load Balancer ID with {@link LoadBalancerContext}
+ * Mapping of Load Balancer ID with {@link L4LoadBalancer}
*/
- private static final Map REGISTRY = new ConcurrentHashMap<>();
+ private static final Map REGISTRY = new ConcurrentHashMap<>();
/**
- * Get mapped {@link LoadBalancerContext} using Load Balancer ID
+ * Get mapped {@link L4LoadBalancer} using Load Balancer ID
*
* @param id Load Balancer ID
- * @return {@link LoadBalancerContext} Instance
- * @throws NullPointerException If {@link LoadBalancerContext} is not found with the ID
+ * @return {@link L4LoadBalancer} Instance
+ * @throws NotFoundException If {@link L4LoadBalancer} is not found with the ID
+ * @throws NullPointerException If {@code id} is {@code null}
*/
- public static LoadBalancerContext get(String id) {
- Objects.requireNonNull(id, "ID cannot be 'null'");
+ public static L4LoadBalancer getContext(String id) {
+ nonNullObject(id, "ID");
+
+ L4LoadBalancer property = REGISTRY.get(id);
- LoadBalancerContext property = REGISTRY.get(id);
- Objects.requireNonNull(property, "Load Balancer was not found with the ID: " + id);
+ if (property == null) {
+ throw new NotFoundException("Load Balancer was not found with the ID: " + id);
+ }
return property;
}
/**
- * Add mapping to {@link LoadBalancerContext} using Load Balancer ID
+ * Add mapping to {@link L4LoadBalancer} using Load Balancer ID
*
- * @param id Load Balancer ID
- * @param context {@link LoadBalancerContext} Instance
- * @throws NullPointerException If {@code id} or {@link LoadBalancerContext} is 'null'
+ * @param id Load Balancer ID
+ * @param context {@link L4LoadBalancer} Instance
+ * @throws NullPointerException If {@code id} or {@link L4LoadBalancer} is 'null'
*/
- public static void add(String id, LoadBalancerContext context) {
- Objects.requireNonNull(id, "ID cannot be 'null'");
- Objects.requireNonNull(context, "Property cannot be 'null'");
+ public static void add(String id, L4LoadBalancer context) {
+ nonNullObject(id, "ID");
+ nonNullObject(context, "LoadBalancerContext");
+
+ if (REGISTRY.containsKey(id)) {
+ throw new IllegalArgumentException("Load Balancer already exists with the ID: " + id);
+ }
REGISTRY.put(id, context);
}
/**
- * Remove mapping of {@link LoadBalancerContext} using Load Balancer ID
+ * Remove mapping of {@link L4LoadBalancer} using Load Balancer ID
*
* @param id Load Balancer ID
- * @return {@link LoadBalancerContext} Instance is successfully removed else {@code null}
+ * @return {@link L4LoadBalancer} Instance is successfully removed else {@code null}
*/
- public static LoadBalancerContext remove(String id) {
- Objects.requireNonNull(id, "ID cannot be 'null'");
+ public static L4LoadBalancer remove(String id) {
+ nonNullObject(id, "ID");
return REGISTRY.remove(id);
}
/**
- * Get total connections across all load balancers.
+ * Get total active connections across all load balancers.
*/
public int totalActiveConnections() {
return REGISTRY.values()
.stream()
- .mapToInt(loadBalancerProperty -> loadBalancerProperty.l4LoadBalancer()
+ .mapToInt(L4LoadBalancer -> L4LoadBalancer
.connectionTracker()
.connections())
.sum();
}
/**
- * Get total connections load across all load balancers
+ * Get the total connections load across all load balancers
*/
public long totalConnections() {
- return REGISTRY.values()
+ return REGISTRY.values()
.stream()
- .mapToLong(value -> value.l4LoadBalancer()
+ .mapToLong(value -> value
.clusters()
.values()
.stream()
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/cluster/LoadBalancerContext.java b/core/src/main/java/com/shieldblaze/expressgateway/core/cluster/LoadBalancerContext.java
deleted file mode 100644
index 6672ff858..000000000
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/cluster/LoadBalancerContext.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * This file is part of ShieldBlaze ExpressGateway. [www.shieldblaze.com]
- * Copyright (c) 2020-2022 ShieldBlaze
- *
- * ShieldBlaze ExpressGateway is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * ShieldBlaze ExpressGateway is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with ShieldBlaze ExpressGateway. If not, see .
- */
-package com.shieldblaze.expressgateway.core.cluster;
-
-import com.shieldblaze.expressgateway.core.events.L4FrontListenerStartupEvent;
-import com.shieldblaze.expressgateway.core.loadbalancer.L4LoadBalancer;
-
-import java.util.Objects;
-
-/**
- * This class holds basic context of a load balancer
- * such as startup timestamp, {@link L4FrontListenerStartupEvent} instance, etc.
- */
-public final class LoadBalancerContext {
-
- // Load Balancer start time
- public static final long STARTUP_TIMESTAMP = System.currentTimeMillis();
- private final L4LoadBalancer l4LoadBalancer;
-
- /**
- * {@link L4LoadBalancer}'s {@link L4FrontListenerStartupEvent} Instance
- */
- private L4FrontListenerStartupEvent startupEvent;
-
- /**
- * Create a new {@link LoadBalancerContext} instance
- *
- * @param l4LoadBalancer {@link L4LoadBalancer} instance
- * @param startupEvent {@link L4FrontListenerStartupEvent} instance
- * @throws NullPointerException If any parameter is 'null'
- */
- public LoadBalancerContext(L4LoadBalancer l4LoadBalancer, L4FrontListenerStartupEvent startupEvent) {
- this.l4LoadBalancer = Objects.requireNonNull(l4LoadBalancer, "L4LoadBalancer cannot be 'null'");
- modifyStartupEvent(startupEvent);
- }
-
- /**
- * Return the associated {@link L4LoadBalancer} Instance
- */
- public L4LoadBalancer l4LoadBalancer() {
- return l4LoadBalancer;
- }
-
- /**
- * Modify the {@link L4FrontListenerStartupEvent} instance with a new instance
- * @param startupEvent {@link L4FrontListenerStartupEvent} instance
- * @throws NullPointerException If the parameter is `null`.
- */
- public void modifyStartupEvent(L4FrontListenerStartupEvent startupEvent) {
- this.startupEvent = Objects.requireNonNull(startupEvent, "L4FrontListenerStartupEvent cannot be 'null'");
- }
-
- /**
- * Return the associated {@link L4FrontListenerStartupEvent} Instance
- */
- public L4FrontListenerStartupEvent modifyStartupEvent() {
- return startupEvent;
- }
-}
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerShutdownEvent.java b/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerShutdownEvent.java
index f8128624d..08d09c691 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerShutdownEvent.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerShutdownEvent.java
@@ -22,7 +22,10 @@
import com.shieldblaze.expressgateway.core.L4FrontListener;
/**
- * {@link Event} for {@link L4FrontListener}
+ * {@link Event} for {@link L4FrontListener}.
+ *
+ *
+ * This event is fired when {@link L4FrontListener} is stopped.
*/
public class L4FrontListenerShutdownEvent extends DefaultEvent {
// Empty
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStartupEvent.java b/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStartupEvent.java
index 57507ab5e..f36f1f1ef 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStartupEvent.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStartupEvent.java
@@ -22,7 +22,8 @@
import com.shieldblaze.expressgateway.core.L4FrontListener;
/**
- *
{@link Event} for {@link L4FrontListener}
+ * {@link Event} for {@link L4FrontListener}
+ *
*
* This event is fired when {@link L4FrontListener} is started.
*/
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStopEvent.java b/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStopEvent.java
index 64c5bc4a4..a56180700 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStopEvent.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/events/L4FrontListenerStopEvent.java
@@ -23,6 +23,9 @@
/**
* {@link Event} for {@link L4FrontListener}
+ *
+ *
+ * This event is fired when {@link L4FrontListener} is stopped.
*/
public class L4FrontListenerStopEvent extends DefaultEvent {
// Empty
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/exceptions/InvalidOperationException.java b/core/src/main/java/com/shieldblaze/expressgateway/core/exceptions/InvalidOperationException.java
new file mode 100644
index 000000000..8124c34e4
--- /dev/null
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/exceptions/InvalidOperationException.java
@@ -0,0 +1,22 @@
+package com.shieldblaze.expressgateway.core.exceptions;
+
+import java.io.Serial;
+
+public final class InvalidOperationException extends RuntimeException {
+
+ @Serial
+ private static final long serialVersionUID = -4203302259240123822L;
+
+ public InvalidOperationException(String message) {
+ super(message);
+ }
+
+ public InvalidOperationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ return this;
+ }
+}
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/exceptions/NotFoundException.java b/core/src/main/java/com/shieldblaze/expressgateway/core/exceptions/NotFoundException.java
new file mode 100644
index 000000000..138f1aa7d
--- /dev/null
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/exceptions/NotFoundException.java
@@ -0,0 +1,29 @@
+package com.shieldblaze.expressgateway.core.exceptions;
+
+import java.io.Serial;
+
+/**
+ *
Exception to be thrown when a resource is not found.
+ */
+public final class NotFoundException extends RuntimeException {
+
+ @Serial
+ private static final long serialVersionUID = -6677068064053200288L;
+
+ public NotFoundException(Type type) {
+ super(type.name() + " not found");
+ }
+
+ public NotFoundException(String message) {
+ super(message);
+ }
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ return this;
+ }
+
+ public enum Type {
+ CLUSTER
+ }
+}
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTimeoutHandler.java b/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTimeoutHandler.java
index 6565e56bd..fad14e159 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTimeoutHandler.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTimeoutHandler.java
@@ -26,9 +26,19 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+/**
+ * {@linkplain ConnectionTimeoutHandler} is a {@linkplain ChannelDuplexHandler} that is used to handle Connection Timeout.
+ *
+ * This Handler is used to handle Connection Timeout for both Upstream and Downstream Connections.
+ *
+ */
public final class ConnectionTimeoutHandler extends ChannelDuplexHandler implements Runnable {
+ /**
+ * Enum to represent the State of Connection Timeout
+ */
public enum State {
+
/**
* When Upstream Read(Receiving) is Idle
*/
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTracker.java b/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTracker.java
index 251f758f7..dd06a46a9 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTracker.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/ConnectionTracker.java
@@ -24,7 +24,7 @@
import java.util.concurrent.atomic.AtomicInteger;
/**
- * {@link ConnectionTracker} tracks number of active connections.
+ * {@link ConnectionTracker} is a special handler that tracks number of active connections.
*/
@ChannelHandler.Sharable
public final class ConnectionTracker extends ChannelInboundHandlerAdapter {
@@ -43,16 +43,22 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
}
+ /**
+ * Increment in the number of active connections
+ */
public void increment() {
connections.incrementAndGet();
}
+ /**
+ * Decrement in the number of active connections
+ */
public void decrement() {
connections.decrementAndGet();
}
/**
- * Get number of active connections
+ * Get the number of active connections
*/
public int connections() {
return connections.get();
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/SNIHandler.java b/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/SNIHandler.java
index 4dc5cfbfe..09cd13936 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/SNIHandler.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/handlers/SNIHandler.java
@@ -31,8 +31,7 @@
import javax.net.ssl.SSLEngine;
/**
- * {@link SNIHandler} TLS Server Name Indication (SNI) and serve the correct
- * {@link CertificateKeyPair} as requested in SNI.
+ * {@link SNIHandler} TLS Server Name Indication (SNI) and serve the correct {@link CertificateKeyPair} as requested in SNI.
*/
public final class SNIHandler extends AbstractSniHandler {
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/DefaultL4LoadBalancer.java b/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/DefaultL4LoadBalancer.java
index ecb28c504..507feea08 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/DefaultL4LoadBalancer.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/DefaultL4LoadBalancer.java
@@ -26,6 +26,9 @@
/**
* Default implementation for {@link L4LoadBalancer}
+ *
+ *
+ * This load balancer will always use {@link L4LoadBalancer#DEFAULT} as hostname.
*/
final class DefaultL4LoadBalancer extends L4LoadBalancer {
@@ -37,8 +40,8 @@ final class DefaultL4LoadBalancer extends L4LoadBalancer {
* @param channelHandler {@link ChannelHandler} to use for handling traffic
* @throws NullPointerException If a required parameter if {@code null}
*/
- DefaultL4LoadBalancer(String name, InetSocketAddress bindAddress, L4FrontListener l4FrontListener, ConfigurationContext configurationContext,
- ChannelHandler channelHandler) {
+ DefaultL4LoadBalancer(String name, InetSocketAddress bindAddress, L4FrontListener l4FrontListener,
+ ConfigurationContext configurationContext, ChannelHandler channelHandler) {
super(name, bindAddress, l4FrontListener, configurationContext, channelHandler);
}
@@ -48,18 +51,19 @@ public Cluster cluster(String hostname) {
}
@Override
- public void mapCluster(String hostname, Cluster cluster) {
- super.mapCluster(DEFAULT, cluster);
+ public void mappedCluster(String hostname, Cluster cluster) {
+ super.mappedCluster(DEFAULT, cluster);
}
@Override
- public void remapCluster(String oldHostname, String newHostname) {
- super.remapCluster(DEFAULT, "DEFAULT");
+ public boolean remapCluster(String oldHostname, String newHostname) {
+ // Always return true because this is a default load balancer and hostname is always DEFAULT.
+ return true;
}
@Override
- public boolean removeCluster(String hostname) {
- return super.removeCluster(DEFAULT);
+ public boolean removeClusters(String hostname) {
+ return super.removeClusters(DEFAULT);
}
@Override
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancer.java b/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancer.java
index 6c4220bd8..c1a5eb633 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancer.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancer.java
@@ -17,6 +17,7 @@
*/
package com.shieldblaze.expressgateway.core.loadbalancer;
+import com.github.f4b6a3.tsid.TsidCreator;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.shieldblaze.expressgateway.backend.cluster.Cluster;
@@ -27,6 +28,7 @@
import com.shieldblaze.expressgateway.core.events.L4FrontListenerShutdownEvent;
import com.shieldblaze.expressgateway.core.events.L4FrontListenerStartupEvent;
import com.shieldblaze.expressgateway.core.events.L4FrontListenerStopEvent;
+import com.shieldblaze.expressgateway.core.exceptions.NotFoundException;
import com.shieldblaze.expressgateway.core.factory.EventLoopFactory;
import com.shieldblaze.expressgateway.core.factory.PooledByteBufAllocatorFactory;
import com.shieldblaze.expressgateway.core.handlers.ConnectionTracker;
@@ -36,12 +38,13 @@
import org.apache.logging.log4j.Logger;
import java.net.InetSocketAddress;
+import java.util.Collections;
import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
+import static java.util.Objects.requireNonNull;
+
/**
* {@link L4LoadBalancer} holds base functions for a L4-Load Balancer.
*/
@@ -50,9 +53,12 @@ public abstract class L4LoadBalancer {
private static final Logger logger = LogManager.getLogger(L4LoadBalancer.class);
public static final String DEFAULT = "DEFAULT";
- private final String ID = UUID.randomUUID().toString();
private static final AtomicInteger COUNTER = new AtomicInteger(0);
+
+ private final String loadBalancerId = TsidCreator.getTsid().toString();
+ private final ConnectionTracker connectionTracker = new ConnectionTracker();
+
private String name = "L4LoadBalancer#" + COUNTER.incrementAndGet();
private final EventStream eventStream;
@@ -66,7 +72,6 @@ public abstract class L4LoadBalancer {
private final EventLoopFactory eventLoopFactory;
private L4FrontListenerStartupEvent l4FrontListenerStartupEvent;
- private final ConnectionTracker connectionTracker = new ConnectionTracker();
/**
* @param name Name of this Load Balancer
@@ -99,12 +104,12 @@ protected L4LoadBalancer(String name,
}
/**
- * Load Balancer UUID
+ * Load Balancer ID
*
- * @return Returns the Load Balancer UUID
+ * @return Returns the Load Balancer ID
*/
public String id() {
- return ID;
+ return loadBalancerId;
}
/**
@@ -191,7 +196,7 @@ public InetSocketAddress bindAddress() {
/**
* Get {@link Cluster} which is being Load Balanced for specific Hostname
*
- * @param hostname FQDN Hostname
+ * @param hostname FQDN to lookup for
* @throws NullPointerException If {@link Cluster} is not found
*/
@NonNull
@@ -199,10 +204,14 @@ public Cluster cluster(String hostname) {
logger.debug("Looking up for Cluster with hostname: {}", hostname);
try {
Cluster cluster = clusterMap.get(hostname);
+
+ // If Cluster is not found, then lookup for DEFAULT Cluster
if (cluster == null) {
+
+ // If DEFAULT Cluster is not found, then throw exception
cluster = clusterMap.get("DEFAULT");
if (cluster == null) {
- throw new NullPointerException("Cluster not found with Hostname: " + hostname);
+ throw new NotFoundException("Cluster not found with Hostname: " + hostname);
}
}
return cluster;
@@ -213,17 +222,26 @@ public Cluster cluster(String hostname) {
}
/**
- * Get all {@link Cluster}
+ * Get all {@link Cluster} instances linked with this Load Balancer
+ *
+ * @return Unmodifiable Map of {@link Cluster} instances
*/
public Map clusters() {
- return clusterMap;
+ return Collections.unmodifiableMap(clusterMap);
+ }
+
+ /**
+ * Remove all Clusters from Load Balancer
+ */
+ public void removeClusters() {
+ clusterMap.clear();
}
/**
* Set the default {@link Cluster}
*/
public void defaultCluster(Cluster cluster) {
- mapCluster("DEFAULT", cluster);
+ mappedCluster("DEFAULT", cluster);
}
/**
@@ -239,9 +257,9 @@ public Cluster defaultCluster() {
* @param hostname Fully qualified Hostname and Port if non-default port is used
* @param cluster {@link Cluster} to be mapped
*/
- public void mapCluster(String hostname, Cluster cluster) {
- Objects.requireNonNull(hostname, "Hostname");
- Objects.requireNonNull(cluster, "Cluster");
+ public void mappedCluster(String hostname, Cluster cluster) {
+ requireNonNull(hostname, "Hostname");
+ requireNonNull(cluster, "Cluster");
try {
logger.info("Mapping Cluster: {} with Hostname: {} and EventStream: {}", cluster, hostname, eventStream);
@@ -261,23 +279,28 @@ public void mapCluster(String hostname, Cluster cluster) {
*
* @param oldHostname Old Hostname
* @param newHostname New Hostname
+ *
+ * @return Returns {@code true} if remapping was successful else {@code false}
*/
- public void remapCluster(String oldHostname, String newHostname) {
- Objects.requireNonNull(oldHostname, "OldHostname");
- Objects.requireNonNull(newHostname, "NewHostname");
+ public boolean remapCluster(String oldHostname, String newHostname) {
+ requireNonNull(oldHostname, "OldHostname");
+ requireNonNull(newHostname, "NewHostname");
try {
logger.info("Remapping Cluster from Hostname: {} to Hostname: {}", oldHostname, newHostname);
Cluster cluster = clusterMap.remove(oldHostname);
+
+ // If Cluster is not found, then return false
if (cluster == null) {
- throw new NullPointerException("Cluster not found with Hostname: " + oldHostname);
+ return false;
}
clusterMap.put(newHostname, cluster);
logger.info("Successfully remapped Cluster: {}, from Hostname: {} to Hostname: {}", cluster, oldHostname, newHostname);
+ return true;
} catch (Exception ex) {
- logger.error("Failed to Remap Cluster", ex);
+ logger.error("Failed to Remap Cluster, oldHostname {}, newHostname {}", oldHostname, newHostname, ex);
throw ex;
}
}
@@ -288,7 +311,7 @@ public void remapCluster(String oldHostname, String newHostname) {
* @param hostname Hostname of the Cluster
* @return Returns {@link Boolean#TRUE} if removal was successful else {@link Boolean#FALSE}
*/
- public boolean removeCluster(String hostname) {
+ public boolean removeClusters(String hostname) {
boolean removed = false;
try {
Cluster cluster = clusterMap.remove(hostname);
@@ -356,6 +379,13 @@ public String toString() {
return "L4LoadBalancer{" + toJson() + '}';
}
+ /**
+ * Get the {@link L4FrontListenerStartupEvent} instance
+ */
+ public L4FrontListenerStartupEvent event() {
+ return l4FrontListenerStartupEvent;
+ }
+
/**
* Convert Load Balancer data into {@link JsonObject}
*
@@ -375,7 +405,7 @@ public JsonObject toJson() {
state = "Pending";
}
- jsonObject.addProperty("ID", ID);
+ jsonObject.addProperty("ID", loadBalancerId);
jsonObject.addProperty("Name", name);
jsonObject.addProperty("Type", type());
jsonObject.addProperty("State", state);
diff --git a/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancerBuilder.java b/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancerBuilder.java
index 45ef1359e..ec02cf970 100644
--- a/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancerBuilder.java
+++ b/core/src/main/java/com/shieldblaze/expressgateway/core/loadbalancer/L4LoadBalancerBuilder.java
@@ -24,6 +24,8 @@
import java.net.InetSocketAddress;
import java.util.Objects;
+import static java.util.Objects.requireNonNull;
+
/**
* Builder for {@link L4LoadBalancer}
*/
@@ -69,9 +71,9 @@ public L4LoadBalancerBuilder withChannelHandler(ChannelHandler channelHandler) {
}
public L4LoadBalancer build() {
- Objects.requireNonNull(bindAddress, "Bind Address");
- Objects.requireNonNull(l4FrontListener, "L4 FrontListener");
- Objects.requireNonNull(configurationContext, "Core Configuration");
+ requireNonNull(bindAddress, "Bind Address");
+ requireNonNull(l4FrontListener, "L4 FrontListener");
+ requireNonNull(configurationContext, "Core Configuration");
return new DefaultL4LoadBalancer(name, bindAddress, l4FrontListener, configurationContext, channelHandler);
}
diff --git a/core/src/test/java/com/shieldblaze/expressgateway/core/cluster/CoreContextTest.java b/core/src/test/java/com/shieldblaze/expressgateway/core/cluster/CoreContextTest.java
index 0c1707efe..3a946e80f 100644
--- a/core/src/test/java/com/shieldblaze/expressgateway/core/cluster/CoreContextTest.java
+++ b/core/src/test/java/com/shieldblaze/expressgateway/core/cluster/CoreContextTest.java
@@ -41,9 +41,9 @@ void simpleAddGetRemoveTest() {
L4FrontListenerStartupEvent l4FrontListenerStartupEvent = l4LoadBalancer.start();
- CoreContext.add(l4LoadBalancer.id(), new LoadBalancerContext(l4LoadBalancer, l4FrontListenerStartupEvent));
- assertEquals(l4FrontListenerStartupEvent, CoreContext.get(l4LoadBalancer.id()).modifyStartupEvent());
- assertEquals(l4FrontListenerStartupEvent, CoreContext.remove(l4LoadBalancer.id()).modifyStartupEvent());
+ CoreContext.add(l4LoadBalancer.id(), l4LoadBalancer);
+ assertEquals(l4FrontListenerStartupEvent, CoreContext.getContext(l4LoadBalancer.id()).event());
+ assertEquals(l4FrontListenerStartupEvent, CoreContext.remove(l4LoadBalancer.id()).event());
}
private static final class DummyL4FrontListener extends L4FrontListener {
diff --git a/pom.xml b/pom.xml
index 0214317e1..7fa384036 100644
--- a/pom.xml
+++ b/pom.xml
@@ -346,6 +346,28 @@ along with ShieldBlaze ExpressGateway. If not, see micrometer-core
1.10.2
+
+
+
+ org.jetbrains
+ annotations
+ 24.1.0
+
+
+
+
+ com.github.f4b6a3
+ tsid-creator
+ 5.2.6
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.36
+ provided
+
diff --git a/protocol-http/src/main/java/com/shieldblaze/expressgateway/protocol/http/compression/CompressionUtil.java b/protocol-http/src/main/java/com/shieldblaze/expressgateway/protocol/http/compression/CompressionUtil.java
index 9fcd7b3a6..ac111ac9e 100644
--- a/protocol-http/src/main/java/com/shieldblaze/expressgateway/protocol/http/compression/CompressionUtil.java
+++ b/protocol-http/src/main/java/com/shieldblaze/expressgateway/protocol/http/compression/CompressionUtil.java
@@ -27,6 +27,7 @@
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
public final class CompressionUtil {
+
private static final boolean EnableBrotli = true;
private static final boolean EnableGzip = true;
private static final boolean EnableDeflate = true;
diff --git a/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/TestableHttpLoadBalancer.java b/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/TestableHttpLoadBalancer.java
index 52981215a..3e1993a80 100644
--- a/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/TestableHttpLoadBalancer.java
+++ b/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/TestableHttpLoadBalancer.java
@@ -82,7 +82,7 @@ public void start() throws Exception {
.withBindAddress(new InetSocketAddress("localhost", 9110))
.build();
- httpLoadBalancer.mapCluster("localhost:9110", cluster);
+ httpLoadBalancer.mappedCluster("localhost:9110", cluster);
NodeBuilder.newBuilder()
.withCluster(cluster)
diff --git a/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/WebsiteProxyTest.java b/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/WebsiteProxyTest.java
index f62f9f215..74c638a95 100644
--- a/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/WebsiteProxyTest.java
+++ b/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/WebsiteProxyTest.java
@@ -57,7 +57,7 @@ public class WebsiteProxyTest {
private static final Logger logger = LogManager.getLogger(WebsiteProxyTest.class);
private static final List WEBSITES = List.of(
- "www.shieldblaze.com"
+ "www.google.com"
);
private static final OkHttpClient OK_HTTP_CLIENT;
@@ -118,7 +118,7 @@ static void setup() throws Exception {
.withSocketAddress(new InetSocketAddress(domain, 443))
.build();
- httpLoadBalancer.mapCluster(domain, cluster);
+ httpLoadBalancer.mappedCluster(domain, cluster);
}
}
diff --git a/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/websocket/WebSocketEchoTest.java b/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/websocket/WebSocketEchoTest.java
index bd16658a8..f10d81891 100644
--- a/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/websocket/WebSocketEchoTest.java
+++ b/protocol-http/src/test/java/com/shieldblaze/expressgateway/protocol/http/websocket/WebSocketEchoTest.java
@@ -70,7 +70,7 @@ static void setup() throws Exception {
.withLoadBalance(new HTTPRoundRobin(NOOPSessionPersistence.INSTANCE))
.build();
- httpLoadBalancer.mapCluster("localhost:9110", cluster);
+ httpLoadBalancer.mappedCluster("localhost:9110", cluster);
NodeBuilder.newBuilder()
.withCluster(cluster)
diff --git a/protocol-tcp/src/main/java/com/shieldblaze/expressgateway/protocol/tcp/TCPListener.java b/protocol-tcp/src/main/java/com/shieldblaze/expressgateway/protocol/tcp/TCPListener.java
index d7da47d16..2c26f70d6 100644
--- a/protocol-tcp/src/main/java/com/shieldblaze/expressgateway/protocol/tcp/TCPListener.java
+++ b/protocol-tcp/src/main/java/com/shieldblaze/expressgateway/protocol/tcp/TCPListener.java
@@ -35,7 +35,6 @@
import io.netty.channel.epoll.EpollServerSocketChannelConfig;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.unix.UnixChannelOption;
-import io.netty.incubator.channel.uring.IOUringChannelOption;
import io.netty.incubator.channel.uring.IOUringServerSocketChannel;
import java.util.List;
@@ -128,7 +127,7 @@ public L4FrontListenerStartupEvent start() {
public L4FrontListenerStopEvent stop() {
L4FrontListenerStopEvent l4FrontListenerStopEvent = new L4FrontListenerStopEvent();
- // If ChannelFutureList is empty then this listener is already stopped and we won't stop it again.
+ // If ChannelFutureList is empty, then this listener is already stopped, and we won't stop it again.
if (channelFutures.isEmpty()) {
l4FrontListenerStopEvent.markFailure(new IllegalArgumentException("Listener has already stopped and cannot be stopped again."));
return l4FrontListenerStopEvent;
@@ -137,7 +136,7 @@ public L4FrontListenerStopEvent stop() {
// Close all ChannelFutures
channelFutures.forEach(channelFuture -> channelFuture.channel().close());
- // Add listener to last ChannelFuture to notify all listeners
+ // Add a listener to last ChannelFuture to notify all listeners
channelFutures.get(channelFutures.size() - 1).channel().closeFuture().addListener(future -> {
if (future.isSuccess()) {
channelFutures.clear();
@@ -159,7 +158,7 @@ public L4FrontListenerShutdownEvent shutdown() {
L4FrontListenerShutdownEvent shutdownEvent = new L4FrontListenerShutdownEvent();
event.future().whenCompleteAsync((_void, throwable) -> {
- l4LoadBalancer().clusters().clear();
+ l4LoadBalancer().removeClusters();
l4LoadBalancer().eventLoopFactory().parentGroup().shutdownGracefully();
l4LoadBalancer().eventLoopFactory().childGroup().shutdownGracefully();
shutdownEvent.markSuccess();
diff --git a/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/cluster/ClusterHandler.java b/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/cluster/ClusterHandler.java
index d20da4ccf..b46079978 100644
--- a/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/cluster/ClusterHandler.java
+++ b/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/cluster/ClusterHandler.java
@@ -36,7 +36,6 @@
import com.shieldblaze.expressgateway.backend.strategy.l7.http.sessionpersistence.StickySession;
import com.shieldblaze.expressgateway.configuration.healthcheck.HealthCheckConfiguration;
import com.shieldblaze.expressgateway.core.cluster.CoreContext;
-import com.shieldblaze.expressgateway.core.cluster.LoadBalancerContext;
import com.shieldblaze.expressgateway.core.loadbalancer.L4LoadBalancer;
import com.shieldblaze.expressgateway.restapi.response.FastBuilder;
import com.shieldblaze.expressgateway.restapi.response.builder.APIResponse;
@@ -61,8 +60,7 @@ public final class ClusterHandler {
@PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public static ResponseEntity create(@RequestParam String id, @RequestBody ClusterContext clusterContext) {
- LoadBalancerContext context = CoreContext.get(id);
- L4LoadBalancer l4LoadBalancer = context.l4LoadBalancer();
+ L4LoadBalancer l4LoadBalancer = CoreContext.getContext(id);
ClusterBuilder clusterBuilder = ClusterBuilder.newBuilder();
if (clusterContext.healthCheckTemplate() != null) {
@@ -72,20 +70,19 @@ public static ResponseEntity create(@RequestParam String id, @RequestBod
determineLoadBalance(l4LoadBalancer, clusterBuilder, clusterContext);
Cluster cluster = clusterBuilder.build();
- l4LoadBalancer.mapCluster(clusterContext.hostname(), cluster);
+ l4LoadBalancer.mappedCluster(clusterContext.hostname(), cluster);
APIResponse apiResponse = APIResponse.newBuilder()
.isSuccess(true)
.withResult(Result.newBuilder().withHeader("Cluster").withMessage(cluster.toJson()).build())
.build();
- return FastBuilder.response(apiResponse.getResponse(), HttpResponseStatus.CREATED);
+ return FastBuilder.response(apiResponse.response(), HttpResponseStatus.CREATED);
}
@PutMapping(value = "/remap", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity remap(@RequestParam String id, @RequestParam String oldHostname, @RequestParam String newHostname) {
- LoadBalancerContext property = CoreContext.get(id);
- L4LoadBalancer l4LoadBalancer = property.l4LoadBalancer();
+ L4LoadBalancer l4LoadBalancer = CoreContext.getContext(id);
l4LoadBalancer.remapCluster(oldHostname, newHostname);
@@ -93,15 +90,15 @@ public ResponseEntity remap(@RequestParam String id, @RequestParam Strin
.isSuccess(true)
.build();
- return FastBuilder.response(apiResponse.getResponse(), HttpResponseStatus.CREATED);
+ return FastBuilder.response(apiResponse.response(), HttpResponseStatus.CREATED);
}
@DeleteMapping(value = "/delete", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity delete(@RequestParam String id, @RequestParam String hostname) {
- LoadBalancerContext property = CoreContext.get(id);
+ L4LoadBalancer l4LoadBalancer = CoreContext.getContext(id);
Objects.requireNonNull(hostname, "Hostname");
- boolean removed = property.l4LoadBalancer().removeCluster(hostname);
+ boolean removed = l4LoadBalancer.removeClusters(hostname);
if (!removed) {
throw new NullPointerException("Cluster not found with Hostname: " + hostname);
}
@@ -110,7 +107,7 @@ public ResponseEntity delete(@RequestParam String id, @RequestParam Stri
.isSuccess(true)
.build();
- return FastBuilder.response(apiResponse.getResponse(), HttpResponseStatus.OK);
+ return FastBuilder.response(apiResponse.response(), HttpResponseStatus.OK);
}
/**
diff --git a/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/configuration/ConfigurationEndpointHandler.java b/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/configuration/ConfigurationEndpointHandler.java
index 2ba8928fd..3a7c160fb 100644
--- a/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/configuration/ConfigurationEndpointHandler.java
+++ b/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/configuration/ConfigurationEndpointHandler.java
@@ -181,7 +181,7 @@ private static ResponseEntity response(Configuration> configuration) t
.withResult(Result.newBuilder().withHeader(configuration.getClass().getSimpleName()).withMessage(json).build())
.build();
- return FastBuilder.response(apiResponse.getResponse(), HttpResponseStatus.OK);
+ return FastBuilder.response(apiResponse.response(), HttpResponseStatus.OK);
}
private static ResponseEntity saveAndGenerateResponse(Configuration> configuration) throws Exception {
@@ -197,7 +197,7 @@ private static ResponseEntity saveAndGenerateResponse(Configuration> c
.withResult(Result.newBuilder().withHeader(StringUtil.simpleClassName(configuration.getClass())).withMessage("Saved").build())
.build();
- return FastBuilder.response(apiResponse.getResponse(), HttpResponseStatus.OK);
+ return FastBuilder.response(apiResponse.response(), HttpResponseStatus.OK);
}
@PostMapping("/tls/client/mapping")
@@ -210,7 +210,7 @@ public ResponseEntity addClientMapping(@RequestBody CertificateKeyPairHo
.isSuccess(true)
.build();
- return FastBuilder.response(apiResponse.getResponse(), HttpResponseStatus.OK);
+ return FastBuilder.response(apiResponse.response(), HttpResponseStatus.OK);
}
@DeleteMapping("/tls/client/mapping")
@@ -224,7 +224,7 @@ public ResponseEntity removeClientMapping(@RequestBody TLSMappingHolder
.isSuccess(true)
.build();
- return FastBuilder.response(apiResponse.getResponse(), HttpResponseStatus.OK);
+ return FastBuilder.response(apiResponse.response(), HttpResponseStatus.OK);
} else {
return FastBuilder.error(ErrorBase.INVALID_REQUEST, "Mapping not found", HttpResponseStatus.NOT_FOUND);
}
diff --git a/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/loadbalancer/LoadBalancerHandler.java b/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/loadbalancer/LoadBalancerHandler.java
index 44981b091..642dba9d3 100644
--- a/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/loadbalancer/LoadBalancerHandler.java
+++ b/rest-api/src/main/java/com/shieldblaze/expressgateway/restapi/api/loadbalancer/LoadBalancerHandler.java
@@ -20,7 +20,6 @@
import com.shieldblaze.expressgateway.configuration.ConfigurationContext;
import com.shieldblaze.expressgateway.core.L4FrontListener;
import com.shieldblaze.expressgateway.core.cluster.CoreContext;
-import com.shieldblaze.expressgateway.core.cluster.LoadBalancerContext;
import com.shieldblaze.expressgateway.core.events.L4FrontListenerStartupEvent;
import com.shieldblaze.expressgateway.core.loadbalancer.L4LoadBalancer;
import com.shieldblaze.expressgateway.core.loadbalancer.L4LoadBalancerBuilder;
@@ -46,16 +45,16 @@
import java.net.InetSocketAddress;
/**
- *
LoadBalancerHandler takes care of fetching registered load balancers,
+ * LoadBalancerHandler takes care of fetching registered load balancers,
* creating new load balancers (L4/L7), stopping load balancers, resuming
- * load balancers and shutting down load balancers.