package com.vtence.molecule.servers; import com.vtence.molecule.Server; import java.lang.reflect.Constructor; import java.util.List; import java.util.Objects; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; public final class Servers { private static final List<String> supported = asList("Simple", "Undertow"); private static final List<? extends Class<? extends Server>> available = supported.stream() .map(Servers::loadClass) .filter(Objects::nonNull) .collect(toList()); private static class NoneAvailableException extends RuntimeException { public String getMessage() { return "No server implementation is available. Add Simple or Undertow jars to your classpath."; } } private static class CreationFailed extends RuntimeException { private final Class<? extends Server> clazz; public CreationFailed(Class<? extends Server> clazz, Throwable cause) { super(cause); this.clazz = clazz; } public String getMessage() { return "Failed to create " + clazz.getSimpleName(); } } private Servers() {} public static Server create(String host, int port) { return available.stream() .map(server -> instantiate(server, host, port)) .findFirst() .orElseThrow(NoneAvailableException::new); } private static Server instantiate(Class<? extends Server> clazz, String host, int port) { try { Constructor<? extends Server> constructor = clazz.getDeclaredConstructor(String.class, Integer.TYPE); return constructor.newInstance(host, port); } catch (Exception e) { throw new CreationFailed(clazz, e); } } private static Class<? extends Server> loadClass(String type) { try { return Class.forName(className(type)).asSubclass(Server.class); } catch (ClassNotFoundException | NoClassDefFoundError notAvailable) { return null; } } private static String className(String type) { return Servers.class.getPackage().getName() + "." + type + "Server"; } }