add Function compiling webapp and update scripts
This commit is contained in:
@@ -38,12 +38,24 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot.experimental</groupId>
|
||||
<artifactId>spring-boot-thin-launcher</artifactId>
|
||||
<version>${wrapper.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.app;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.cloud.function.compiler.CompiledFunctionFactory;
|
||||
import org.springframework.cloud.function.compiler.ConsumerCompiler;
|
||||
import org.springframework.cloud.function.compiler.FunctionCompiler;
|
||||
import org.springframework.cloud.function.compiler.SupplierCompiler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class CompiledFunctionRegistry {
|
||||
|
||||
private static final String SUPPLIER_DIRECTORY = "suppliers";
|
||||
|
||||
private static final String FUNCTION_DIRECTORY = "functions";
|
||||
|
||||
private static final String CONSUMER_DIRECTORY = "consumers";
|
||||
|
||||
private final File supplierDirectory;
|
||||
|
||||
private final File functionDirectory;
|
||||
|
||||
private final File consumerDirectory;
|
||||
|
||||
private final SupplierCompiler<Flux<?>> supplierCompiler = new SupplierCompiler<>();
|
||||
|
||||
private final FunctionCompiler<Flux<?>, Flux<?>> functionCompiler = new FunctionCompiler<>();
|
||||
|
||||
private final ConsumerCompiler<?> consumerCompiler = new ConsumerCompiler<>();
|
||||
|
||||
public CompiledFunctionRegistry() {
|
||||
this(new File("/tmp/function-registry"));
|
||||
}
|
||||
|
||||
public CompiledFunctionRegistry(File directory) {
|
||||
Assert.notNull(directory, "Directory must not be null");
|
||||
if (!directory.exists()) {
|
||||
directory.mkdirs();
|
||||
}
|
||||
else {
|
||||
Assert.isTrue(directory.isDirectory(),
|
||||
String.format("%s is not a directory.", directory.getAbsolutePath()));
|
||||
}
|
||||
this.supplierDirectory = new File(directory, SUPPLIER_DIRECTORY);
|
||||
this.functionDirectory = new File(directory, FUNCTION_DIRECTORY);
|
||||
this.consumerDirectory = new File(directory, CONSUMER_DIRECTORY);
|
||||
this.supplierDirectory.mkdir();
|
||||
this.functionDirectory.mkdir();
|
||||
this.consumerDirectory.mkdir();
|
||||
}
|
||||
|
||||
public void registerSupplier(String name, String supplier) {
|
||||
CompiledFunctionFactory<?> factory = this.supplierCompiler.compile(name, supplier);
|
||||
File file = new File(this.supplierDirectory, fileName(name));
|
||||
try {
|
||||
FileCopyUtils.copy(factory.getGeneratedClassBytes(), file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException(String.format("failed to register Supplier: %s", name), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerFunction(String name, String function) {
|
||||
CompiledFunctionFactory<?> factory = this.functionCompiler.compile(name, function);
|
||||
File file = new File(this.functionDirectory, fileName(name));
|
||||
try {
|
||||
FileCopyUtils.copy(factory.getGeneratedClassBytes(), file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException(String.format("failed to register Function: %s", name), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerConsumer(String name, String consumer) {
|
||||
CompiledFunctionFactory<?> factory = this.consumerCompiler.compile(name, consumer);
|
||||
File file = new File(this.consumerDirectory, fileName(name));
|
||||
try {
|
||||
FileCopyUtils.copy(factory.getGeneratedClassBytes(), file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException(String.format("failed to register Consumer: %s", name), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String fileName(String functionName) {
|
||||
return String.format("%s.%s", functionName, "fun");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.app;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class CompilerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CompilerApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.app;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
@RestController
|
||||
public class CompilerController {
|
||||
|
||||
private final CompiledFunctionRegistry registry = new CompiledFunctionRegistry();
|
||||
|
||||
@PostMapping(path = "/{type}/{name}")
|
||||
public void registerFunction(@PathVariable String type, @PathVariable String name, @RequestBody String lambda) {
|
||||
switch (type) {
|
||||
case "supplier":
|
||||
registry.registerSupplier(name, lambda);
|
||||
break;
|
||||
case "function":
|
||||
registry.registerFunction(name, lambda);
|
||||
break;
|
||||
case "consumer":
|
||||
registry.registerConsumer(name, lambda);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.proxy;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cloud.function.compiler.CompilationResultFactory;
|
||||
import org.springframework.cloud.function.compiler.FunctionCompiler;
|
||||
import org.springframework.cloud.function.compiler.java.SimpleClassLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public abstract class AbstractByteCodeLoadingProxy<T> implements InitializingBean {
|
||||
|
||||
private final Resource resource;
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private T target;
|
||||
|
||||
private final SimpleClassLoader classLoader = new SimpleClassLoader(AbstractByteCodeLoadingProxy.class.getClassLoader());
|
||||
|
||||
public AbstractByteCodeLoadingProxy(Resource resource, Class<?> type) {
|
||||
this.resource = resource;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
byte[] bytes = FileCopyUtils.copyToByteArray(this.resource.getInputStream());
|
||||
String functionName = this.resource.getFilename().replaceAll(".fun$", "");
|
||||
String firstLetter = functionName.substring(0, 1).toUpperCase();
|
||||
String upperCasedName = (functionName.length() > 1) ? firstLetter + functionName.substring(1) : firstLetter;
|
||||
String className = String.format("%s.%s%sFactory", FunctionCompiler.class.getPackage().getName(), upperCasedName, this.type.getSimpleName());
|
||||
Class<?> factoryClass = this.classLoader.defineClass(className, bytes);
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
CompilationResultFactory<T> factory = (CompilationResultFactory<T>) factoryClass.newInstance();
|
||||
this.target = factory.getResult();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("failed to load Function byte code", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected final T getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.proxy;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*
|
||||
* @param <T> type
|
||||
*/
|
||||
public class ByteCodeLoadingConsumer<T> extends AbstractByteCodeLoadingProxy<Consumer<T>> implements Consumer<T> {
|
||||
|
||||
public ByteCodeLoadingConsumer(Resource resource) {
|
||||
super(resource, Consumer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(T t) {
|
||||
this.getTarget().accept(t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.proxy;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*
|
||||
* @param <T> Function input type
|
||||
* @param <R> Function result type
|
||||
*/
|
||||
public class ByteCodeLoadingFunction<T, R> extends AbstractByteCodeLoadingProxy<Function<T, R>> implements Function<T, R>, InitializingBean {
|
||||
|
||||
public ByteCodeLoadingFunction(Resource resource) {
|
||||
super(resource, Function.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R apply(T input) {
|
||||
return this.getTarget().apply(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler.proxy;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*
|
||||
* @param <T> type
|
||||
*/
|
||||
public class ByteCodeLoadingSupplier<T> extends AbstractByteCodeLoadingProxy<Supplier<T>> implements Supplier<T> {
|
||||
|
||||
public ByteCodeLoadingSupplier(Resource resource) {
|
||||
super(resource, Supplier.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return this.getTarget().get();
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.compiler;
|
||||
package org.springframework.cloud.function.compiler.proxy;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.function.Function;
|
||||
Reference in New Issue
Block a user