Re-factor Listeners and Resolvers to use ServiceLoader protocol discovery
This commit is contained in:
parent
0bca5ee0a2
commit
f118f6410b
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -6,30 +6,21 @@ import com.moparisthebest.dns.resolve.Resolver;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
public interface Listener extends Runnable, AutoCloseable {
|
public interface Listener extends Runnable, AutoCloseable {
|
||||||
public static Listener of(final String listener, final Resolver resolver, final ExecutorService executor) {
|
|
||||||
/*
|
ServiceLoader<Services> services = ServiceLoader.load(Services.class);
|
||||||
listener = listener.trim().toLowerCase();
|
|
||||||
final String[] hostPort = listener.substring(6).split(":");
|
static Listener of(final String listener, final Resolver resolver, final ExecutorService executor) {
|
||||||
//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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
final ParsedUrl parsedUrl = ParsedUrl.of(listener);
|
final ParsedUrl parsedUrl = ParsedUrl.of(listener);
|
||||||
switch(parsedUrl.getProtocol()) {
|
for (final Services s : services) {
|
||||||
case "tcp":
|
final Listener ret = s.getListener(parsedUrl, resolver, executor);
|
||||||
return new TcpAsync(parsedUrl.getAddr(), resolver, executor);
|
if (ret != null)
|
||||||
case "udp":
|
return ret;
|
||||||
return new UdpSync(parsedUrl.getAddr(), resolver, executor);
|
|
||||||
}
|
}
|
||||||
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) {
|
public static Listener ofAndStart(final String listener, final Resolver resolver, final ExecutorService executor) {
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -11,13 +11,15 @@ import java.util.*;
|
|||||||
|
|
||||||
public class ParsedUrl {
|
public class ParsedUrl {
|
||||||
|
|
||||||
|
private final String urlStr;
|
||||||
private final SocketAddress addr;
|
private final SocketAddress addr;
|
||||||
private final URI uri; // minus #
|
private final URI uri; // minus #
|
||||||
private final Map<String, String> props; // after #, split by ;
|
private final Map<String, String> props; // after #, split by ;
|
||||||
private final Proxy proxy;
|
private final Proxy proxy;
|
||||||
private final SSLSocketFactory sslSocketFactory;
|
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.addr = addr;
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.props = props;
|
this.props = props;
|
||||||
@ -70,7 +72,7 @@ public class ParsedUrl {
|
|||||||
}
|
}
|
||||||
if(sslSocketFactory == null && url.getScheme().equals("tls"))
|
if(sslSocketFactory == null && url.getScheme().equals("tls"))
|
||||||
sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
|
sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
|
||||||
return new ParsedUrl(addr, url, props, proxy, sslSocketFactory);
|
return new ParsedUrl(urlStr, addr, url, props, proxy, sslSocketFactory);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof RuntimeException)
|
if (e instanceof RuntimeException)
|
||||||
throw (RuntimeException) e;
|
throw (RuntimeException) e;
|
||||||
@ -104,6 +106,10 @@ public class ParsedUrl {
|
|||||||
return toUrlRemoveRef(uri);
|
return toUrlRemoveRef(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUrlStr() {
|
||||||
|
return urlStr;
|
||||||
|
}
|
||||||
|
|
||||||
public SocketAddress getAddr() {
|
public SocketAddress getAddr() {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
@ -29,17 +29,6 @@ public abstract class AbstractQueueProcessingResolver implements QueueProcessing
|
|||||||
executor.execute(this);
|
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
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
thisThread = Thread.currentThread();
|
thisThread = Thread.currentThread();
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ import java.net.*;
|
|||||||
|
|
||||||
import static com.moparisthebest.dns.Util.readPacket;
|
import static com.moparisthebest.dns.Util.readPacket;
|
||||||
|
|
||||||
public class HttpResolver extends AbstractQueueProcessingResolver {
|
public class HttpResolver implements Resolver {
|
||||||
private final OpenConnection openConnection;
|
private final OpenConnection openConnection;
|
||||||
private final int connectTimeout;
|
private final int connectTimeout;
|
||||||
private final int readTimeout = 4000;
|
private final int readTimeout = 4000;
|
||||||
@ -18,8 +18,7 @@ public class HttpResolver extends AbstractQueueProcessingResolver {
|
|||||||
HttpURLConnection open() throws Exception;
|
HttpURLConnection open() throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpResolver(final int maxRetries, final String name, final URL url, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
|
public HttpResolver(final URL url, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
|
||||||
super(maxRetries, name);
|
|
||||||
this.connectTimeout = connectTimeout;
|
this.connectTimeout = connectTimeout;
|
||||||
if(proxy == null && sslSocketFactory == null) {
|
if(proxy == null && sslSocketFactory == null) {
|
||||||
openConnection = () -> (HttpURLConnection) url.openConnection();
|
openConnection = () -> (HttpURLConnection) url.openConnection();
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
package com.moparisthebest.dns.resolve;
|
package com.moparisthebest.dns.resolve;
|
||||||
|
|
||||||
import com.moparisthebest.dns.dto.Packet;
|
|
||||||
import com.moparisthebest.dns.net.ParsedUrl;
|
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.Map;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
public interface QueueProcessingResolver extends Resolver, Runnable, AutoCloseable {
|
public interface QueueProcessingResolver extends Resolver, Runnable, AutoCloseable {
|
||||||
@ -27,15 +22,6 @@ public interface QueueProcessingResolver extends Resolver, Runnable, AutoCloseab
|
|||||||
String name = parsedUrl.getProps().get("name");
|
String name = parsedUrl.getProps().get("name");
|
||||||
if(name == null)
|
if(name == null)
|
||||||
name = parsedUrl.getUri().toString();
|
name = parsedUrl.getUri().toString();
|
||||||
final int connectTimeout = Integer.parseInt(parsedUrl.getProps().getOrDefault("connectTimeout", "500"));
|
return new DelegatingQueueProcessingResolver(maxRetries, name, Resolver.of(parsedUrl));
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,32 @@
|
|||||||
package com.moparisthebest.dns.resolve;
|
package com.moparisthebest.dns.resolve;
|
||||||
|
|
||||||
import com.moparisthebest.dns.dto.Packet;
|
import com.moparisthebest.dns.dto.Packet;
|
||||||
import com.moparisthebest.dns.listen.Listener;
|
import com.moparisthebest.dns.net.ParsedUrl;
|
||||||
import com.moparisthebest.dns.listen.TcpAsync;
|
|
||||||
import com.moparisthebest.dns.listen.UdpSync;
|
|
||||||
|
|
||||||
import javax.net.SocketFactory;
|
import java.util.ServiceLoader;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public interface Resolver {
|
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;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.moparisthebest.dns.resolve;
|
||||||
|
|
||||||
|
import com.moparisthebest.dns.net.ParsedUrl;
|
||||||
|
|
||||||
|
public interface Services {
|
||||||
|
Resolver getResolver(ParsedUrl parsedUrl);
|
||||||
|
}
|
@ -14,7 +14,7 @@ import static com.moparisthebest.dns.Util.readTcpPacket;
|
|||||||
import static com.moparisthebest.dns.Util.tryClose;
|
import static com.moparisthebest.dns.Util.tryClose;
|
||||||
import static com.moparisthebest.dns.Util.writeTcpPacket;
|
import static com.moparisthebest.dns.Util.writeTcpPacket;
|
||||||
|
|
||||||
public class SocketResolver extends AbstractQueueProcessingResolver {
|
public class SocketResolver implements Resolver {
|
||||||
private final OpenSocket openConnection;
|
private final OpenSocket openConnection;
|
||||||
private final int readTimeout = 4000;
|
private final int readTimeout = 4000;
|
||||||
|
|
||||||
@ -22,8 +22,7 @@ public class SocketResolver extends AbstractQueueProcessingResolver {
|
|||||||
Socket open() throws Exception;
|
Socket open() throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketResolver(final int maxRetries, final String name, final SocketAddress endpoint, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
|
public SocketResolver(final SocketAddress endpoint, final int connectTimeout, final Proxy proxy, final SSLSocketFactory sslSocketFactory) {
|
||||||
super(maxRetries, name);
|
|
||||||
if(proxy == null && sslSocketFactory == null) {
|
if(proxy == null && sslSocketFactory == null) {
|
||||||
openConnection = () -> {
|
openConnection = () -> {
|
||||||
Socket s = null;
|
Socket s = null;
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
com.moparisthebest.dns.listen.DefaultServices
|
@ -0,0 +1 @@
|
|||||||
|
com.moparisthebest.dns.resolve.DefaultServices
|
Loading…
Reference in New Issue
Block a user