package edu.berkeley.thebes.common.config; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Map; import com.google.common.collect.Lists; import edu.berkeley.thebes.common.config.ConfigParameterTypes.AtomicityLevel; import edu.berkeley.thebes.common.config.ConfigParameterTypes.IsolationLevel; import edu.berkeley.thebes.common.config.ConfigParameterTypes.PersistenceEngine; import edu.berkeley.thebes.common.config.ConfigParameterTypes.RoutingMode; import edu.berkeley.thebes.common.config.ConfigParameterTypes.SessionLevel; import edu.berkeley.thebes.common.config.ConfigParameterTypes.TransactionMode; /** * These define parameters that can have default values or be set by * configuration or command-line interfaces. */ public enum ConfigParameters { CONFIG_FILE(String.class, "conf/thebes.yaml"), CLUSTERID(Integer.class, RequirementLevel.COMMON), /** 0 to N-1, exactly N servers per cluster */ SERVERID(Integer.class, RequirementLevel.SERVER_COMMON), CLIENTID(Short.class, RequirementLevel.CLIENT_COMMON), /** Map of clusters, indexed starting at 1. */ CLUSTER_CONFIG(Map.class, RequirementLevel.HAT_COMMON), GRAPHITE_IP(String.class, ""), PERSISTENCE_ENGINE(PersistenceEngine.class, PersistenceEngine.MEMORY), PENDING_WRITES_DB(String.class, "pending.db"), SOCKET_TIMEOUT(Integer.class, 4000), SERVER_PORT(Integer.class, 8080), ANTI_ENTROPY_PORT(Integer.class, 8081), ANTI_ENTROPY_THREADS(Integer.class, 10), TA_ANTI_ENTROPY_THREADS(Integer.class, 2), TA_BATCH_TIME(Integer.class, 10000), STANDALONE(Boolean.class, false), ROUTING_MODE(RoutingMode.class, RoutingMode.NEAREST), QUORUM_THREADS(Integer.class, 10), TXN_MODE(TransactionMode.class, RequirementLevel.CLIAPP), HAT_ISOLATION_LEVEL(IsolationLevel.class, IsolationLevel.NO_ISOLATION), ANTIENTROPY_BOOTSTRAP_TIME(Integer.class, 30*1000), TWOPL_PORT(Integer.class, 8082), TWOPL_REPLICATE_TO_SLAVES(Boolean.class, true), TWOPL_TM_PORT(Integer.class, 8083), TWOPL_TM_CONFIG(Map.class, RequirementLevel.TWOPL_TM), TWOPL_CLUSTER_CONFIG(Map.class, RequirementLevel.TWOPL_COMMON), TWOPL_USE_TM(Boolean.class, true), SESSION_LEVEL(SessionLevel.class, SessionLevel.NO_SESSION), ATOMICITY_LEVEL(AtomicityLevel.class, AtomicityLevel.NO_ATOMICITY), LOGGER_LEVEL(String.class, "WARN"), DISK_DATABASE_FILE(String.class, "/tmp/thebes.db"), DO_CLEAN_DATABASE_FILE(Boolean.class, true), DATABASE_CACHE_SIZE(Integer.class, -1), METRICS_TO_CONSOLE(Boolean.class, false), STORE_PENDING_IN_MEMORY(Boolean.class, false); /** Note that defaultValue and reqLevels are mutually exclusive. */ private Class<?> type; private Object defaultValue; private RequirementLevel[] reqLevels; private <T> ConfigParameters(Class<T> type, Object defaultValue) { this.type = type; this.defaultValue = defaultValue; this.reqLevels = new RequirementLevel[]{}; } private <T> ConfigParameters(Class<T> type, RequirementLevel reqLevel) { this.type = type; this.defaultValue = null; this.reqLevels = new RequirementLevel[]{ reqLevel }; } private <T> ConfigParameters(Class<T> type, RequirementLevel ... reqLevels) { this.type = type; this.defaultValue = null; this.reqLevels = reqLevels; } public String getTextName() { return this.name().toLowerCase(); } public Object getDefaultValue() { return defaultValue; } public boolean requiresLevel(RequirementLevel reqLevel) { for (RequirementLevel level : reqLevels) { if (level == reqLevel) { return true; } } return false; } public Object castValue(Object o) { // If our type is already a superclass of o, we can just return! if (type.isAssignableFrom(o.getClass())) { return o; // Casting to custom enumeration types. See {@link ConfigParameterTypes}. } else if (Arrays.asList(type.getInterfaces()).contains(ConfigParameterTypes.class)) { assert o instanceof String; try { Method m = type.getMethod("valueOf", String.class); String key = o.toString().toUpperCase(); return m.invoke(null, key); } catch (Exception e) { throw new IllegalArgumentException("Cannot cast " + o + " to " + type); } // Boolean casting } else if (type.equals(Boolean.class)) { if (Lists.newArrayList("", "true", "on").contains(o)) { return Boolean.TRUE; } else if (Lists.newArrayList("false", "off").contains(o)) { return Boolean.FALSE; } // String->Integer casting } else if (type.equals(Integer.class) && o instanceof String) { return Integer.parseInt(o.toString()); } else if (type.equals(Short.class) && o instanceof String) { return Short.parseShort(o.toString()); } throw new IllegalArgumentException("Cannot convert " + o.getClass() + " to " + type); } }