I have two environment PROD
and STAGING
. In prod environment we have three datacenters ABC
, DEF
and PQR
and stag
I started off with this but got confuse on how can I have single key for each DC and then multiple values as List of machines for that DC and then I need to group them by environment as well.
You forgot an important just : enum may store members (method and fields) specific to each enum value but it may also store static
members if required.
What you need is moving the maps that groups by environment directly in the enum class :
private static final ImmutableMap> PROD_SERVERS_BY_DC;
private static final ImmutableMap> STAGING_SERVERS_BY_DC;
You could use an inner map to return the expected map according to the user request :
private static final Map>> SERVERS_BY_ENV;
Where Env
is another enum :
public static enum Env {
PROD, STAGING
}
In the code that I will present I added as an enclosing type of Datacenter
but it would be probably better in its own file as the environment is probably not a concept used exclusively by datacenters.
At last, the way you are using to retrieve servers by environment splits related responsibilities in 2 classes (Datacenter
enum and the current class) :
Map> machinesByDC = Utils.isProd() ? Utils.PROD_SERVERS_BY_DC : Utils.STAGING_SERVERS_BY_DC;
introducing in the enum a method to do this operation would be nicer :
public static ImmutableMap> getServers(Env env){...}
Which would increase the cohesion of the enum class.
Here is the enum updated :
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
public enum Datacenter {
ABC(Env.PROD, "tcp://machineA:8081", "tcp://machineA:8082"),
DEF(Env.PROD, "tcp://machineB:8081", "tcp://machineB:8082"),
PQR(Env.PROD, "tcp://machineA:8081", "tcp://machineA:8082"),
CORP(Env.STAGING, "tcp://machineC:8081", "tcp://machineC:8082");
public static enum Env {
PROD, STAGING
}
private Env env;
private String[] url;
private static final ImmutableMap> PROD_SERVERS_BY_DC;
private static final ImmutableMap> STAGING_SERVERS_BY_DC;
private static final Map>> SERVERS_BY_ENV;
static {
Builder> prodDataCenterBuilder = ImmutableMap.>builder();
Builder> stagingDataCenterBuilder = ImmutableMap.>builder();
for (Datacenter datacenter : Datacenter.values()) {
if (datacenter.env == Env.PROD) {
prodDataCenterBuilder.put(datacenter, ImmutableList.of(datacenter.url));
} else if (datacenter.env == Env.STAGING) {
stagingDataCenterBuilder.put(datacenter, ImmutableList.of(datacenter.url));
}
else {
throw new IllegalArgumentException("not exepected env " + datacenter.env);
}
}
PROD_SERVERS_BY_DC = prodDataCenterBuilder.build();
STAGING_SERVERS_BY_DC = stagingDataCenterBuilder.build();
SERVERS_BY_ENV = new HashMap<>();
SERVERS_BY_ENV.put(Env.PROD, PROD_SERVERS_BY_DC);
SERVERS_BY_ENV.put(Env.STAGING, STAGING_SERVERS_BY_DC);
}
Datacenter(Env env, String... url) {
this.env = env;
this.url = url;
}
public static ImmutableMap> getServers(Env env) {
ImmutableMap> map = SERVERS_BY_ENV.get(env);
if (map == null) {
throw new IllegalArgumentException("not exepected env " + env);
}
return map;
}
}
And here how to use it :
public static void main(String[] args) {
ImmutableMap> servers = Datacenter.getServers(Env.PROD);
servers.forEach((k, v) -> System.out.println("prod datacenter=" + k + ", urls=" + v));
servers = Datacenter.getServers(Env.STAGING);
servers.forEach((k, v) -> System.out.println("staging datacenter=" + k + ", urls=" + v));
}
Output :
prod datacenter=ABC, urls=[tcp://machineA:8081, tcp://machineA:8082]
prod datacenter=DEF, urls=[tcp://machineB:8081, tcp://machineB:8082]
prod datacenter=PQR, urls=[tcp://machineA:8081, tcp://machineA:8082]
staging datacenter=CORP, urls=[tcp://machineC:8081, tcp://machineC:8082]