code: package io.paradoxical.cassieq.environment;
  
  import com.datastax.driver.core.ConsistencyLevel;
  import com.google.common.base.Strings;
  import io.paradoxical.cassieq.configurations.AllocationStrategy;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.lang.reflect.Proxy;
  import java.util.Arrays;
  import java.util.List;
  import java.util.Optional;
  import java.util.stream.Collectors;
  
  public interface SystemProps {
      @Env(defaultValue = "/data/db", help = "The location of the cql scripts for bootstrapping/dev mode")
      String DB_SCRIPTS_PATH();
  
      @Env(defaultValue = "cassieq", help = "The cassandra cluster name")
      String CLUSTER_NAME();
  
      @Env(defaultValue = "192.168.99.100", help = "The cassandra cluster contact points")
      String CONTACT_POINTS();
  
      @Env(defaultValue = "cassieq", help = "The cassandra keyspace cassieq lives in")
      String KEYSPACE();
  
      @Env(defaultValue = "9042", help = "The cassandra cql client port")
      Integer CASSANDRA_PORT();
  
      @Env(defaultValue = "", help = "The cassandra username")
      String USERNAME();
  
      @Env(defaultValue = "", help = "The cassandra password")
      String PASSWORD();
  
      @Env(defaultValue = "500", help = "The max number of connections to a remote data center")
      Integer REMOTE_MAX_CONNECTIONS();
  
      @Env(defaultValue = "LOCAL_QUORUM", help = "The consistency level of queries")
      ConsistencyLevel CONSISTENCY_LEVEL();
  
      @Env(defaultValue = "false", help = "Enable or disable https")
      Boolean HTTPS();
  
      @Env(defaultValue = "PKCS12", help = "The https keystore type")
      String HTTPS_KEY_STORE_TYPE();
  
      @Env(defaultValue = "/data/https/serverKeys.p12", help = "The keystore path")
      String HTTPS_KEY_STORE_PATH();
  
      @Env(defaultValue = "", help = "The keystore password")
      String HTTPS_KEY_STORE_PASSWORD();
  
      @Env(defaultValue = "true", help = "Whether to do cert validation or not")
      Boolean HTTPS_VALIDATE_CERTS();
  
      @Env(defaultValue = "NONE", help = "The repair worker queue distribution strategy")
      AllocationStrategy ALLOCATION_STRATEGY();
  
      @Env(defaultValue = "false", help = "Enable graphite publishing")
      Boolean USE_METRICS_GRAPHITE();
  
      @Env(defaultValue = "192.168.99.100", help = "The graphite endpoint url")
      String GRAPHITE_URL();
  
      @Env(defaultValue = "2003", help = "The graphite port")
      Integer GRAPHITE_PORT();
  
      @Env(defaultValue = "", help = "The graphite prefix")
      String GRAPHITE_PREFIX();
  
      @Env(defaultValue = "*", help = "Allowed CORS origins (comma separated)")
      String CORS_ALLOWED_ORIGINS();
  
      @Env(defaultValue = "false", help = "Log raw requests to console")
      Boolean LOG_RAW_REQUESTS();
  
      static List<SystemPropDiscovery> discover() {
          return Arrays.asList(SystemProps.class.getMethods())
                       .stream()
                       .map(method -> {
                           if (Modifier.isStatic(method.getModifiers())) {
                               return null;
                           }
  
                           final Env env = method.getAnnotation(Env.class);
  
                           String envVarName = method.getName();
  
                           try {
                               return new SystemPropDiscovery(env.help(), env.defaultValue(), envVarName, getFromMethod(method));
                           }
                           catch (Exception e) {
                               throw new RuntimeException("Error getting value!", e);
                           }
                       })
                       .filter(m -> m != null)
                       .collect(Collectors.toList());
      }
  
      static SystemProps instance() {
          return (SystemProps) Proxy.newProxyInstance(
                  SystemProps.class.getClassLoader(),
                  new Class[]{ SystemProps.class },
                  (proxy, method, args) -> getFromMethod(method));
      }
  
      static Object getFromMethod(Method method) throws InvocationTargetException, IllegalAccessException {
          final Class<?> returnType = method.getReturnType();
  
          String envVar = System.getenv(method.getName());
  
          if (Strings.isNullOrEmpty(envVar)) {
              envVar = method.getAnnotation(Env.class).defaultValue();
          }
  
          if (returnType.isInstance(String.class)) {
              return envVar;
          }
  
          /**
           * Mistyping a boolean as "true1" just evaluates to false... why java why..
           */
          if(returnType.isAssignableFrom(Boolean.class) && !(envVar.equals("true") || envVar.equals("false"))){
              throw new RuntimeException("Boolean variable should be either true or false but was " +  envVar);
          }
  
          final Optional<Method> valueOfStringConverter
                  = Arrays.asList(returnType.getMethods())
                          .stream()
                          .filter(i -> i.getName().equals("valueOf")
                                       && i.getParameterCount() == 1 &&
                                       i.getParameterTypes()[0].isAssignableFrom(String.class))
                          .findFirst();
  
          if (valueOfStringConverter.isPresent()) {
              return valueOfStringConverter.get().invoke(null, envVar);
          }
  
          throw new RuntimeException("Could not convert string to type: " + method.getName());
      }
  
  
  }
  