Re-factor Listeners and Resolvers to use ServiceLoader protocol discovery

This commit is contained in:
Travis Burtrum 2019-03-13 00:01:48 -04:00
parent 0bca5ee0a2
commit f118f6410b
14 changed files with 128 additions and 61 deletions

View File

@ -0,0 +1,19 @@
package com.moparisthebest.dns.listen;
import com.moparisthebest.dns.net.ParsedUrl;
import com.moparisthebest.dns.resolve.Resolver;
import java.util.concurrent.ExecutorService;
public class DefaultServices implements Services {
@Override
public Listener getListener(ParsedUrl parsedUrl, final Resolver resolver, final ExecutorService executor) {
switch(parsedUrl.getProtocol()) {
case "tcp":
return new TcpAsync(parsedUrl.getAddr(), resolver, executor);
case "udp":
return new UdpSync(parsedUrl.getAddr(), resolver, executor);
}
return null;
}
}

View File

@ -6,30 +6,21 @@ import com.moparisthebest.dns.resolve.Resolver;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutorService;
public interface Listener extends Runnable, AutoCloseable {
public static Listener of(final String listener, final Resolver resolver, final ExecutorService executor) {
/*
listener = listener.trim().toLowerCase();
final String[] hostPort = listener.substring(6).split(":");
//System.out.println("hostPort: " + Arrays.toString(hostPort));
final SocketAddress socketAddress = new InetSocketAddress(hostPort[0], Integer.parseInt(hostPort[1]));
//System.out.println("socketAddress: " + socketAddress);
if(listener.startsWith("tcp://")) {
return new TcpAsync(socketAddress, resolver, executor);
} else if(listener.startsWith("udp://")) {
return new UdpSync(socketAddress, resolver, executor);
}
*/
ServiceLoader<Services> services = ServiceLoader.load(Services.class);
static Listener of(final String listener, final Resolver resolver, final ExecutorService executor) {
final ParsedUrl parsedUrl = ParsedUrl.of(listener);
switch(parsedUrl.getProtocol()) {
case "tcp":
return new TcpAsync(parsedUrl.getAddr(), resolver, executor);
case "udp":
return new UdpSync(parsedUrl.getAddr(), resolver, executor);
for (final Services s : services) {
final Listener ret = s.getListener(parsedUrl, resolver, executor);
if (ret != null)
return ret;
}
throw new IllegalArgumentException("invalid listener format");
throw new IllegalArgumentException("unhandled listener format: " + listener);
}
public static Listener ofAndStart(final String listener, final Resolver resolver, final ExecutorService executor) {

View File

@ -0,0 +1,10 @@
package com.moparisthebest.dns.listen;
import com.moparisthebest.dns.net.ParsedUrl;
import com.moparisthebest.dns.resolve.Resolver;
import java.util.concurrent.ExecutorService;
public interface Services {
Listener getListener(ParsedUrl parsedUrl, Resolver resolver, ExecutorService executor);
}

View File

@ -11,13 +11,15 @@ import java.util.*;
public class ParsedUrl {
private final String urlStr;
private final SocketAddress addr;
private final URI uri; // minus #
private final Map<String, String> props; // after #, split by ;
private final Proxy proxy;
private final SSLSocketFactory sslSocketFactory;
public ParsedUrl(final SocketAddress addr, final URI uri, final Map<String, String> props, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
public ParsedUrl(final String urlStr, final SocketAddress addr, final URI uri, final Map<String, String> props, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
this.urlStr = urlStr;
this.addr = addr;
this.uri = uri;
this.props = props;
@ -70,7 +72,7 @@ public class ParsedUrl {
}
if(sslSocketFactory == null && url.getScheme().equals("tls"))
sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
return new ParsedUrl(addr, url, props, proxy, sslSocketFactory);
return new ParsedUrl(urlStr, addr, url, props, proxy, sslSocketFactory);
} catch (Exception e) {
if (e instanceof RuntimeException)
throw (RuntimeException) e;
@ -104,6 +106,10 @@ public class ParsedUrl {
return toUrlRemoveRef(uri);
}
public String getUrlStr() {
return urlStr;
}
public SocketAddress getAddr() {
return addr;
}

View File

@ -29,17 +29,6 @@ public abstract class AbstractQueueProcessingResolver implements QueueProcessing
executor.execute(this);
}
@Override
public <E extends RequestResponse> CompletableFuture<E> resolveAsync(final E requestResponse) {
return null;
/*
return CompletableFuture.supplyAsync(() -> {
requestResponse.setResponse(resolve(requestResponse.getRequest()));
return requestResponse;
}, executor);
*/
}
@Override
public void run() {
thisThread = Thread.currentThread();

View File

@ -0,0 +1,19 @@
package com.moparisthebest.dns.resolve;
import com.moparisthebest.dns.net.ParsedUrl;
public class DefaultServices implements Services {
@Override
public Resolver getResolver(ParsedUrl parsedUrl) {
final int connectTimeout = Integer.parseInt(parsedUrl.getProps().getOrDefault("connectTimeout", "500"));
switch(parsedUrl.getProtocol()) {
case "tcp":
case "tls":
return new SocketResolver(parsedUrl.getAddr(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory());
case "http":
case "https":
return new HttpResolver(parsedUrl.getUrlWithoutFragment(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory());
}
return null;
}
}

View File

@ -0,0 +1,25 @@
package com.moparisthebest.dns.resolve;
import com.moparisthebest.dns.dto.Packet;
import java.util.concurrent.CompletableFuture;
public class DelegatingQueueProcessingResolver extends AbstractQueueProcessingResolver {
private final Resolver delegate;
public DelegatingQueueProcessingResolver(final int maxRetries, final String name, final Resolver delegate) {
super(maxRetries, name);
this.delegate = delegate;
}
@Override
public <E extends RequestResponse> CompletableFuture<E> resolveAsync(final E requestResponse) {
return delegate.resolveAsync(requestResponse);
}
@Override
public Packet resolve(final Packet request) throws Exception {
return delegate.resolve(request);
}
}

View File

@ -9,7 +9,7 @@ import java.net.*;
import static com.moparisthebest.dns.Util.readPacket;
public class HttpResolver extends AbstractQueueProcessingResolver {
public class HttpResolver implements Resolver {
private final OpenConnection openConnection;
private final int connectTimeout;
private final int readTimeout = 4000;
@ -18,8 +18,7 @@ public class HttpResolver extends AbstractQueueProcessingResolver {
HttpURLConnection open() throws Exception;
}
public HttpResolver(final int maxRetries, final String name, final URL url, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
super(maxRetries, name);
public HttpResolver(final URL url, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
this.connectTimeout = connectTimeout;
if(proxy == null && sslSocketFactory == null) {
openConnection = () -> (HttpURLConnection) url.openConnection();

View File

@ -1,14 +1,9 @@
package com.moparisthebest.dns.resolve;
import com.moparisthebest.dns.dto.Packet;
import com.moparisthebest.dns.net.ParsedUrl;
import javax.net.SocketFactory;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
public interface QueueProcessingResolver extends Resolver, Runnable, AutoCloseable {
@ -27,15 +22,6 @@ public interface QueueProcessingResolver extends Resolver, Runnable, AutoCloseab
String name = parsedUrl.getProps().get("name");
if(name == null)
name = parsedUrl.getUri().toString();
final int connectTimeout = Integer.parseInt(parsedUrl.getProps().getOrDefault("connectTimeout", "500"));
switch(parsedUrl.getProtocol()) {
case "tcp":
case "tls":
return new SocketResolver(maxRetries, name, parsedUrl.getAddr(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory());
case "http":
case "https":
return new HttpResolver(maxRetries, name, parsedUrl.getUrlWithoutFragment(), connectTimeout, parsedUrl.getProxy(), parsedUrl.getSslSocketFactory());
}
throw new IllegalArgumentException("invalid listener format");
return new DelegatingQueueProcessingResolver(maxRetries, name, Resolver.of(parsedUrl));
}
}

View File

@ -1,17 +1,32 @@
package com.moparisthebest.dns.resolve;
import com.moparisthebest.dns.dto.Packet;
import com.moparisthebest.dns.listen.Listener;
import com.moparisthebest.dns.listen.TcpAsync;
import com.moparisthebest.dns.listen.UdpSync;
import com.moparisthebest.dns.net.ParsedUrl;
import javax.net.SocketFactory;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ServiceLoader;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
public interface Resolver {
<E extends RequestResponse> CompletableFuture<E> resolveAsync(E requestResponse);
default <E extends RequestResponse> CompletableFuture<E> resolveAsync(E requestResponse) {
return null;
/*
return CompletableFuture.supplyAsync(() -> {
requestResponse.setResponse(resolve(requestResponse.getRequest()));
return requestResponse;
}, executor);
*/
}
Packet resolve(Packet request) throws Exception;
ServiceLoader<Services> services = ServiceLoader.load(Services.class);
static Resolver of(final ParsedUrl parsedUrl) {
for (final Services s : services) {
final Resolver ret = s.getResolver(parsedUrl);
if (ret != null)
return ret;
}
throw new IllegalArgumentException("unhandled resolver format: " + parsedUrl.getUrlStr());
}
}

View File

@ -0,0 +1,7 @@
package com.moparisthebest.dns.resolve;
import com.moparisthebest.dns.net.ParsedUrl;
public interface Services {
Resolver getResolver(ParsedUrl parsedUrl);
}

View File

@ -14,7 +14,7 @@ import static com.moparisthebest.dns.Util.readTcpPacket;
import static com.moparisthebest.dns.Util.tryClose;
import static com.moparisthebest.dns.Util.writeTcpPacket;
public class SocketResolver extends AbstractQueueProcessingResolver {
public class SocketResolver implements Resolver {
private final OpenSocket openConnection;
private final int readTimeout = 4000;
@ -22,8 +22,7 @@ public class SocketResolver extends AbstractQueueProcessingResolver {
Socket open() throws Exception;
}
public SocketResolver(final int maxRetries, final String name, final SocketAddress endpoint, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
super(maxRetries, name);
public SocketResolver(final SocketAddress endpoint, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
if(proxy == null && sslSocketFactory == null) {
openConnection = () -> {
Socket s = null;

View File

@ -0,0 +1 @@
com.moparisthebest.dns.listen.DefaultServices

View File

@ -0,0 +1 @@
com.moparisthebest.dns.resolve.DefaultServices