diff --git a/src/main/java/io/projectriff/invoker/FunctionConfiguration.java b/src/main/java/io/projectriff/invoker/FunctionConfiguration.java index fbdfd33..864605b 100644 --- a/src/main/java/io/projectriff/invoker/FunctionConfiguration.java +++ b/src/main/java/io/projectriff/invoker/FunctionConfiguration.java @@ -22,7 +22,9 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -133,16 +135,23 @@ public void init() { } private URL[] expand(URL[] urls) { - if (urls.length != 1 || !"file".equals(urls[0].getProtocol())) { - return urls; + List result = new ArrayList<>(); + for (URL url : urls) { + result.addAll(expand(url)); + } + return result.toArray(new URL[0]); + } + + private List expand(URL url) { + if (!"file".equals(url.getProtocol())) { + return Collections.singletonList(url); } - URL url = urls[0]; if (!url.toString().endsWith(".jar")) { - return urls; + return Collections.singletonList(url); } try { JarFileArchive archive = new JarFileArchive(new File(url.toURI())); - return new ComputeLauncher(archive).getClassLoaderUrls(); + return Arrays.asList(new ComputeLauncher(archive).getClassLoaderUrls()); } catch (Exception e) { throw new IllegalStateException("Cannot create class loader for " + url, e); diff --git a/src/main/java/io/projectriff/invoker/GrpcConfiguration.java b/src/main/java/io/projectriff/invoker/GrpcConfiguration.java index dbd344e..b7ad9ff 100644 --- a/src/main/java/io/projectriff/invoker/GrpcConfiguration.java +++ b/src/main/java/io/projectriff/invoker/GrpcConfiguration.java @@ -71,7 +71,7 @@ public void setPort(int port) { /** Start serving requests. */ @EventListener(ContextRefreshedEvent.class) - public void start() throws IOException { + public void start() { try { Function, Flux> function = catalog.lookup(Function.class, functions.getFunctionName()); @@ -88,7 +88,7 @@ public void start() throws IOException { this.server.start(); } catch (IOException e) { - throw new IOException(String + throw new IllegalStateException(String .format("gRPC server failed to start listening on port %d", port), e); } logger.info("Server started, listening on " + port); diff --git a/src/test/java/io/projectriff/invoker/ComposedJavaFunctionInvokerApplicationTests.java b/src/test/java/io/projectriff/invoker/ComposedJavaFunctionInvokerApplicationTests.java index 897fe21..85fd37d 100644 --- a/src/test/java/io/projectriff/invoker/ComposedJavaFunctionInvokerApplicationTests.java +++ b/src/test/java/io/projectriff/invoker/ComposedJavaFunctionInvokerApplicationTests.java @@ -42,8 +42,8 @@ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @DirtiesContext -@TestPropertySource(properties = "function.uri=file:target/test-classes" - + "?handler=io.projectriff.functions.Doubler,io.projectriff.functions.Frenchizer") +@TestPropertySource(properties = {"grpc.port=0", "function.uri=file:target/test-classes" + + "?handler=io.projectriff.functions.Doubler,io.projectriff.functions.Frenchizer"}) public class ComposedJavaFunctionInvokerApplicationTests { @Autowired diff --git a/src/test/java/io/projectriff/invoker/FatJarPojoTests.java b/src/test/java/io/projectriff/invoker/FatJarPojoTests.java index 0f80206..17c2e97 100644 --- a/src/test/java/io/projectriff/invoker/FatJarPojoTests.java +++ b/src/test/java/io/projectriff/invoker/FatJarPojoTests.java @@ -44,6 +44,7 @@ public class FatJarPojoTests { private File sampleJar; private JavaFunctionInvokerApplication runner; + private File sampleDir; @Before public void init() { @@ -60,6 +61,7 @@ public void close() throws Exception { @Before public void check() { + sampleDir = new File("target/it/pojo/target/classes"); sampleJar = new File( "target/it/pojo/target/function-sample-pojo-1.0.0.BUILD-SNAPSHOT.jar"); Assume.assumeTrue("Sample jar does not exist: " + sampleJar, sampleJar.exists()); @@ -78,4 +80,16 @@ public void fatJar() throws Exception { assertThat(result.getBody()).isEqualTo("[{\"value\":\"FOO\"}]"); } + @Test + public void fatJarAndDirectory() throws Exception { + runner.run("--server.port=" + port, "--grpc.port=0", + "--function.uri=" + sampleDir.toURI() + "," + sampleJar.toURI() + + "?handler=uppercase&main=com.example.SampleApplication"); + ResponseEntity result = rest.exchange(RequestEntity + .post(new URI("http://localhost:" + port + "/")) + .contentType(MediaType.APPLICATION_JSON).body("{\"value\":\"foo\"}"), + String.class); + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(result.getBody()).isEqualTo("[{\"value\":\"FOO\"}]"); + } } diff --git a/src/test/java/io/projectriff/invoker/JavaFunctionInvokerApplicationTests.java b/src/test/java/io/projectriff/invoker/JavaFunctionInvokerApplicationTests.java index 7702c8b..592d901 100644 --- a/src/test/java/io/projectriff/invoker/JavaFunctionInvokerApplicationTests.java +++ b/src/test/java/io/projectriff/invoker/JavaFunctionInvokerApplicationTests.java @@ -41,8 +41,8 @@ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @DirtiesContext -@TestPropertySource(properties = "function.uri=file:target/test-classes" - + "?handler=io.projectriff.functions.Doubler") +@TestPropertySource(properties = { "grpc.port=0", "function.uri=file:target/test-classes" + + "?handler=io.projectriff.functions.Doubler" }) public class JavaFunctionInvokerApplicationTests { @Autowired