Skip to content

Commit

Permalink
When a transport is loaded by the service loader mechanism, Vert.x sh…
Browse files Browse the repository at this point in the history
…ould check the transport is available before using it.
  • Loading branch information
vietj committed May 2, 2023
1 parent 0175ed3 commit f6a37b4
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 16 deletions.
7 changes: 5 additions & 2 deletions src/main/java/io/vertx/core/impl/VertxBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,11 @@ static Transport findTransport(boolean preferNative) {
if (preferNative) {
Collection<Transport> transports = ServiceHelper.loadFactories(Transport.class);
Iterator<Transport> it = transports.iterator();
if (it.hasNext()) {
return it.next();
while (it.hasNext()) {
Transport transport = it.next();
if (transport.isAvailable()) {
return transport;
}
}
Transport nativeTransport = nativeTransport();
if (nativeTransport != null && nativeTransport.isAvailable()) {
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/io/vertx/core/impl/ServiceLoaderTransportTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.vertx.core.impl;

import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.spi.transport.Transport;
import io.vertx.test.core.AsyncTestBase;
import io.vertx.test.core.TestUtils;
import io.vertx.test.faketransport.FakeTransport;
import org.junit.Test;

public class ServiceLoaderTransportTest extends AsyncTestBase {

@Test
public void testServiceLoaderTransportNotAvailable() {
Vertx vertx = TestUtils.runWithServiceLoader(Transport.class, FakeTransport.class, () ->
Vertx.vertx(new VertxOptions().setPreferNativeTransport(true)));
assertNotSame(FakeTransport.class, ((VertxInternal)vertx).transport());
}
}
15 changes: 5 additions & 10 deletions src/test/java/io/vertx/core/spi/metrics/MetricsOptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void testMetricsFromServiceLoader() {
vertx.close();
MetricsOptions metricsOptions = new MetricsOptions().setEnabled(true);
VertxOptions options = new VertxOptions().setMetricsOptions(metricsOptions);
vertx = createVertxLoadingMetricsFromMetaInf(options, "io.vertx.test.fakemetrics.FakeMetricsFactory");
vertx = createVertxLoadingMetricsFromMetaInf(options, io.vertx.test.fakemetrics.FakeMetricsFactory.class);
VertxMetrics metrics = ((VertxInternal) vertx).metricsSPI();
assertNotNull(metrics);
assertTrue(metrics instanceof FakeVertxMetrics);
Expand All @@ -106,19 +106,14 @@ public void testSetMetricsInstanceTakesPrecedenceOverServiceLoader() {
DummyVertxMetrics metrics = DummyVertxMetrics.INSTANCE;
vertx.close();
VertxOptions options = new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(new SimpleVertxMetricsFactory<>(metrics)));
vertx = createVertxLoadingMetricsFromMetaInf(options, "io.vertx.test.fakemetrics.FakeMetricsFactory");
vertx = createVertxLoadingMetricsFromMetaInf(options, io.vertx.test.fakemetrics.FakeMetricsFactory.class);
assertSame(metrics, ((VertxInternal) vertx).metricsSPI());
}

static Vertx createVertxLoadingMetricsFromMetaInf(VertxOptions options, String factoryFqn) {
ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
ClassLoader cl = createMetricsFromMetaInfLoader(factoryFqn);
Thread.currentThread().setContextClassLoader(cl);
try {
static Vertx createVertxLoadingMetricsFromMetaInf(VertxOptions options, Class<? extends VertxServiceProvider> factory) {
return TestUtils.runWithServiceLoader(VertxServiceProvider.class, factory, () -> {
return Vertx.vertx(options);
} finally {
Thread.currentThread().setContextClassLoader(oldCL);
}
});
}

public static ClassLoader createMetricsFromMetaInfLoader(String factoryFqn) {
Expand Down
32 changes: 28 additions & 4 deletions src/test/java/io/vertx/test/core/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.cert.Certificate;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
Expand Down Expand Up @@ -542,4 +541,29 @@ public static Throwable rootCause(Throwable throwable) {
}
return root;
}


public static <T, S> T runWithServiceLoader(Class<S> service, Class<? extends S> impl, Supplier<T> supplier) {
URLClassLoader cl = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()) {
@Override
public Enumeration<URL> findResources(String name) throws IOException {
if (name.equals("META-INF/services/" + service.getName())) {
File f = File.createTempFile("vertx", ".txt");
f.deleteOnExit();
Files.write(f.toPath(), impl.getName().getBytes());
return Collections.enumeration(Collections.singleton(f.toURI().toURL()));
}
return super.findResources(name);
}
};
Thread th = Thread.currentThread();
ClassLoader previousCL = th.getContextClassLoader();
th.setContextClassLoader(cl);
try {
return supplier.get();
} finally {
th.setContextClassLoader(previousCL);
}
}

}
51 changes: 51 additions & 0 deletions src/test/java/io/vertx/test/faketransport/FakeTransport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.vertx.test.faketransport;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFactory;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.InternetProtocolFamily;
import io.vertx.core.spi.transport.Transport;

import java.util.concurrent.ThreadFactory;

public class FakeTransport implements Transport {

private static final Throwable CAUSE = new UnsupportedOperationException("Unavailable");

@Override
public boolean isAvailable() {
return false;
}

@Override
public Throwable unavailabilityCause() {
return CAUSE;
}

@Override
public EventLoopGroup eventLoopGroup(int type, int nThreads, ThreadFactory threadFactory, int ioRatio) {
throw new UnsupportedOperationException();
}

@Override
public DatagramChannel datagramChannel() {
throw new UnsupportedOperationException();
}

@Override
public DatagramChannel datagramChannel(InternetProtocolFamily family) {
throw new UnsupportedOperationException();
}

@Override
public ChannelFactory<? extends Channel> channelFactory(boolean domainSocket) {
throw new UnsupportedOperationException();
}

@Override
public ChannelFactory<? extends ServerChannel> serverChannelFactory(boolean domainSocket) {
throw new UnsupportedOperationException();
}
}

0 comments on commit f6a37b4

Please sign in to comment.