Skip to content

Instantly share code, notes, and snippets.

@zeryx
Last active May 3, 2019 20:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeryx/e933adefaaae1ea1cbfd8f9f5a20d6a3 to your computer and use it in GitHub Desktop.
Save zeryx/e933adefaaae1ea1cbfd8f9f5a20d6a3 to your computer and use it in GitHub Desktop.
package AlgorithmHandler.algorithms;
import java.util.HashMap;
public class AdvancedAlgorithm {
public class AlgoInput {
String name;
Integer age;
}
public String Apply(AlgoInput input, HashMap<String, String> context) throws Exception {
if (context.containsKey("local_file")) {
return "Hello " + input.name + " you are " + input.age +
" years old, and your model file is downloaded here " + context.get("local_file");
}
return "hello " + input.name + " you are " + input.age + " years old";
}
public HashMap<String, String> DownloadModel() throws Exception {
HashMap<String, String> context = new HashMap<>();
context.put("local_file", "/tmp/somefile");
return context;
}
}
package AlgorithmHandler;
import AlgorithmHandler.algorithms.AdvancedAlgorithm;
import com.algorithmia.algorithmHandler.AlgorithmHandler;
import com.google.gson.JsonObject;
import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
public class AdvancedAlgorithmTest extends AlgorithmHandlerTestBase {
@Test
public void RunAlgorithm()throws Exception{
JsonObject expectedResponse = new JsonObject();
JsonObject metadata = new JsonObject();
metadata.addProperty("content_type", "text");
expectedResponse.add("metadata", metadata);
expectedResponse.addProperty("result", "Hello james");
AdvancedAlgorithm algo = new AdvancedAlgorithm();
AlgorithmHandler handler = new AlgorithmHandler<>(algo::Apply, algo::DownloadModel);
InputStream fakeIn = new ByteArrayInputStream("{\"content_type\":\"json\", \"data\":{\"name\":\"james\", \"age\":25}}".getBytes());
System.setIn(fakeIn);
handler.run();
byte[] fifoBytes = Files.readAllBytes(Paths.get(FIFOPIPE));
String rawData = new String(fifoBytes);
JsonObject actualResponse = parser.parse(rawData).getAsJsonObject();
Assert.assertEquals(expectedResponse, actualResponse);
}
}
package com.algorithmia.algorithmHandler;
import java.io.IOException;
// The user can define nearly any type of Input, State, and Output arguments, they don't need to be json serializable.
public class AlgorithmHandler<INPUT, STATE, OUTPUT> {
@FunctionalInterface
public interface BifunctionWithException<INPUT, STATE, OUTPUT> {
OUTPUT apply(INPUT t, STATE j) throws Throwable;
}
@FunctionalInterface
public interface FunctionWithException<INPUT, OUTPUT>{
OUTPUT apply(INPUT t) throws Throwable;
}
@FunctionalInterface
public interface SupplierWithException<STATE> {
STATE apply() throws Throwable;
}
private BifunctionWithException<INPUT, STATE, OUTPUT> applyWState;
private FunctionWithException<INPUT, OUTPUT> apply;
private SupplierWithException<STATE> loadFunc;
private STATE state;
private void Load() throws Throwable{
state = this.loadFunc.apply();
System.out.println("PIPE_INIT_COMPLETE");
System.out.flush();
}
private void ExecuteWithoutState(RequestHandler<INPUT> in, ResponseHandler out) throws Throwable {
INPUT req = in.GetNextRequest();
while(req != null){
OUTPUT output = this.apply.apply(req);
out.writeToPipe(output);
req = in.GetNextRequest();
}
}
private void ExecuteWithState(RequestHandler<INPUT> in, ResponseHandler out) throws Throwable{
INPUT req = in.GetNextRequest();
while (req != null) {
OUTPUT output = this.applyWState.apply(req, state);
out.writeToPipe(output);
req = in.GetNextRequest();
}
}
public AlgorithmHandler(BifunctionWithException<INPUT, STATE, OUTPUT> applyWState, SupplierWithException<STATE> loadFunc){
this.applyWState = applyWState;
this.loadFunc = loadFunc;
}
public AlgorithmHandler(BifunctionWithException<INPUT, STATE, OUTPUT> applyWState){
this.applyWState = applyWState;
}
public AlgorithmHandler(FunctionWithException<INPUT, OUTPUT> apply){
this.apply = apply;
}
public void setLoad(SupplierWithException<STATE> func){
loadFunc = func;
}
public void run() throws IOException {
RequestHandler<INPUT> in = new RequestHandler<>();
ResponseHandler out = new ResponseHandler();
try {
if(this.applyWState != null && this.loadFunc != null) {
Load();
ExecuteWithState(in, out);
} else {
ExecuteWithoutState(in, out);
}
} catch (Throwable e){
out.writeErrorToPipe(e);
}
}
}
package com.algorithmia.algorithmHandler;
import com.google.gson.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Scanner;
import org.apache.commons.codec.binary.Base64;
final class RequestHandler<INPUT>
{
private Scanner input;
private JsonParser parser;
private Gson gson;
RequestHandler(){
this.input = new Scanner(System.in);
this.parser = new JsonParser();
this.gson = new Gson();
}
//This function doesn't work, I don't know how to do this kind of branching paths with generic types.
INPUT ProcessRequest(Request request) throws Exception{
INPUT response;
Type type = this.getClass().getTypeParameters()[0];
if(type instanceof Class){
response = gson.fromJson(request.data, ((Class) types[0]).getGenericSuperclass());
} else if(types[0] instanceof String.class){
response = (INPUT)request.data.getAsString();
}
else if(types[0] instanceof JsonElement){
response = (INPUT)request.data;
}
else{
response = (INPUT)Base64.decodeBase64(request.data.getAsString());
}
return request;
}
INPUT GetNextRequest() throws Exception{
if(input.hasNextLine()){
String line = input.nextLine();
JsonObject json = parser.parse(line).getAsJsonObject();
String contentType = json.get("content_type").getAsString();
JsonElement data = json.get("data");
Request request = new Request(contentType, data);
return ProcessRequest(request);
}
else {
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment