ソースを参照

adding tuProlog (#6766)

vka 4 年 前
コミット
12342f930e

+ 1 - 1
frameworks/Prolog/SWI-Prolog/app/server.pl

@@ -14,7 +14,7 @@
 server(Port) :-
     odbc_set_option(connection_pooling(true)),
     current_prolog_flag(cpu_count, Cores),
-    Workers is 256 * Cores,
+    Workers is 64 * Cores,
     http_server(http_dispatch, [workers(Workers), port(Port), timeout(30)]).
 
 

+ 3 - 0
frameworks/Prolog/tuProlog/.gitignore

@@ -0,0 +1,3 @@
+/.idea
+/target
+tuprolog.iml

+ 5 - 0
frameworks/Prolog/tuProlog/app/application.prolog

@@ -0,0 +1,5 @@
+:- web_resource(plaintext/1, content_type(text/plain)).
+plaintext('Hello, World!').
+
+:- web_resource(json/1).
+json([message('Hello, World!')]).

+ 24 - 0
frameworks/Prolog/tuProlog/benchmark_config.json

@@ -0,0 +1,24 @@
+{
+  "framework": "tuprolog",
+  "tests": [{
+    "default": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "None",
+      "database": "None",
+      "framework": "tuprolog",
+      "language": "Prolog",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "Vert.x",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "tuProlog",
+      "notes": "",
+      "versus": "",
+      "tags": []
+    }
+  }]
+}

+ 15 - 0
frameworks/Prolog/tuProlog/config.toml

@@ -0,0 +1,15 @@
+[framework]
+name = "tuprolog"
+
+[main]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+approach = "Realistic"
+classification = "None"
+database = "None"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "None"
+webserver = "Vert.x"
+versus = ""

+ 69 - 0
frameworks/Prolog/tuProlog/pom.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.kartashov.fb</groupId>
+    <artifactId>tuprolog-web-runner</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>16</maven.compiler.source>
+        <maven.compiler.target>16</maven.compiler.target>
+        <tuprolog.version>0.18.2</tuprolog.version>
+        <vertx.version>4.1.2</vertx.version>
+        <jackson.version>2.12.3</jackson.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>it.unibo.tuprolog</groupId>
+            <artifactId>io-lib-jvm</artifactId>
+            <version>${tuprolog.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>it.unibo.tuprolog</groupId>
+            <artifactId>solve-classic-jvm</artifactId>
+            <version>${tuprolog.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.vertx</groupId>
+            <artifactId>vertx-web</artifactId>
+            <version>${vertx.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>com.kartashov.fb.tuprolog.Runner</mainClass>
+                        </manifest>
+                    </archive>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 72 - 0
frameworks/Prolog/tuProlog/src/main/java/com/kartashov/fb/tuprolog/Engine.java

@@ -0,0 +1,72 @@
+package com.kartashov.fb.tuprolog;
+
+import com.kartashov.fb.tuprolog.processors.DirectiveProcessor;
+import com.kartashov.fb.tuprolog.processors.WebResourceDirectiveProcessor;
+import io.vertx.core.http.HttpServerRequest;
+import it.unibo.tuprolog.core.Struct;
+import it.unibo.tuprolog.core.Var;
+import it.unibo.tuprolog.solve.MutableSolver;
+import it.unibo.tuprolog.solve.Solver;
+import it.unibo.tuprolog.theory.Theory;
+import it.unibo.tuprolog.theory.parsing.ClausesReader;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Engine {
+
+    private final Map<String, Resource> resources = new HashMap<>();
+    private final MutableSolver solver = Solver.getClassic().mutableSolverWithDefaultBuiltins();
+
+    public Engine(String... paths) {
+        Theory theory = Theory.empty();
+        ClausesReader reader = ClausesReader.getWithDefaultOperators();
+        for (var path : paths) {
+            try {
+                var stream = new FileInputStream(Paths.get(path).toFile());
+                var subTheory = reader.readTheory(stream);
+                for (var processor : processors()) {
+                    subTheory = processor.apply(subTheory, this);
+                }
+                theory = theory.plus(subTheory);
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException("Cannot load file", e);
+            }
+        }
+        solver.loadStaticKb(theory);
+    }
+
+    public void addResource(String path, Resource resource) {
+        resources.put(path, resource);
+    }
+
+    public void resolve(HttpServerRequest request) {
+        var resource = resources.get(request.path());
+        if (resource == null) {
+            request.response().setStatusCode(404).end();
+            return;
+        }
+        var goalTerm = Struct.of(resource.predicate(), Var.of("Response"));
+        var solution = solver.solveOnce(goalTerm);
+        if (solution.isYes()) {
+            var responseTerm = solution.getSubstitution().getByName("Response");
+            if (responseTerm == null) {
+                request.response().setStatusCode(503).end();
+            } else {
+                resource.writer().write(request.response(), responseTerm);
+            }
+        } else {
+            request.response().setStatusCode(404).end();
+        }
+    }
+
+    private List<DirectiveProcessor> processors() {
+        return List.of(
+                new WebResourceDirectiveProcessor()
+        );
+    }
+}

+ 34 - 0
frameworks/Prolog/tuProlog/src/main/java/com/kartashov/fb/tuprolog/Resource.java

@@ -0,0 +1,34 @@
+package com.kartashov.fb.tuprolog;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.kartashov.fb.tuprolog.visitors.TermToJavaObjectConverterVisitor;
+import io.vertx.core.http.HttpServerResponse;
+import it.unibo.tuprolog.core.Term;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+
+public record Resource(String predicate, Writer writer) {
+    public record Writer(String contentType) {
+        public void write(HttpServerResponse response, Term term) {
+            response.putHeader("Server", "tuProlog");
+            response.putHeader("Date", DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()));
+            response.putHeader("Content-Type", contentType);
+            switch (contentType) {
+                case "application/json" -> {
+                    var visitor = new TermToJavaObjectConverterVisitor();
+                    var value = term.accept(visitor);
+                    var mapper = new ObjectMapper();
+                    try {
+                        response.end(mapper.writeValueAsString(value));
+                    } catch (JsonProcessingException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+                case "text/plain" -> response.end(Objects.requireNonNull(term.asAtom()).getValue());
+            }
+        }
+    }
+}

+ 12 - 0
frameworks/Prolog/tuProlog/src/main/java/com/kartashov/fb/tuprolog/Runner.java

@@ -0,0 +1,12 @@
+package com.kartashov.fb.tuprolog;
+
+import io.vertx.core.Vertx;
+
+public class Runner {
+    public static void main(String... args) {
+        var engine = new Engine(args);
+        var server = Vertx.vertx().createHttpServer();
+        server.requestHandler(engine::resolve);
+        server.listen(8080);
+    }
+}

+ 42 - 0
frameworks/Prolog/tuProlog/src/main/java/com/kartashov/fb/tuprolog/processors/DirectiveProcessor.java

@@ -0,0 +1,42 @@
+package com.kartashov.fb.tuprolog.processors;
+
+import com.kartashov.fb.tuprolog.Engine;
+import it.unibo.tuprolog.core.Struct;
+import it.unibo.tuprolog.core.Term;
+import it.unibo.tuprolog.theory.Theory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public abstract class DirectiveProcessor {
+
+    abstract String functor();
+
+    protected Theory apply(Struct target, Map<String, Term> properties, Theory theory, Engine engine) {
+        return theory;
+    }
+
+    final public Theory apply(Theory theory, Engine engine) {
+        for (var directive: theory.getDirectives()) {
+            var body = directive.getBody().asStruct();
+            if (body == null || !body.getFunctor().equals(functor())) {
+                continue;
+            }
+            Struct target = null;
+            var properties = new HashMap<String, Term>();
+            var i = 0;
+            for (var arg: body.getArgs()) {
+                Struct argStruct = Objects.requireNonNull(arg.asStruct());
+                if (i++ == 0) {
+                    target = argStruct;
+                } else {
+                    properties.put(argStruct.getFunctor(), argStruct.getArgAt(0));
+                }
+            }
+            theory = apply(target, properties, theory, engine);
+        }
+        return theory;
+    }
+}
+

+ 32 - 0
frameworks/Prolog/tuProlog/src/main/java/com/kartashov/fb/tuprolog/processors/WebResourceDirectiveProcessor.java

@@ -0,0 +1,32 @@
+package com.kartashov.fb.tuprolog.processors;
+
+import com.kartashov.fb.tuprolog.Engine;
+import com.kartashov.fb.tuprolog.Resource;
+import it.unibo.tuprolog.core.Struct;
+import it.unibo.tuprolog.core.Term;
+import it.unibo.tuprolog.theory.Theory;
+
+import java.util.Map;
+import java.util.Objects;
+
+public class WebResourceDirectiveProcessor extends DirectiveProcessor {
+
+    @Override
+    String functor() {
+        return "web_resource";
+    }
+
+    @Override
+    protected Theory apply(Struct target, Map<String, Term> properties, Theory theory, Engine engine) {
+
+        var predicate = Objects.requireNonNull(target.getArgAt(0).asAtom()).getValue();
+        var arity = Objects.requireNonNull(target.getArgAt(1).asInteger()).getValue().toInt();
+        // @todo check arity for better match
+        var contentTypeTerm = properties.get("content_type");
+        var contentType = contentTypeTerm != null ? contentTypeTerm.toString() : "application/json";
+
+        engine.addResource("/" + predicate, new Resource(predicate, new Resource.Writer(contentType)));
+        return theory;
+    }
+}
+

+ 60 - 0
frameworks/Prolog/tuProlog/src/main/java/com/kartashov/fb/tuprolog/visitors/TermToJavaObjectConverterVisitor.java

@@ -0,0 +1,60 @@
+package com.kartashov.fb.tuprolog.visitors;
+
+import it.unibo.tuprolog.core.Integer;
+import it.unibo.tuprolog.core.*;
+import it.unibo.tuprolog.core.visitors.DefaultTermVisitor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class TermToJavaObjectConverterVisitor extends DefaultTermVisitor<Object> {
+
+    @Override
+    public Object defaultValue(@NotNull Term term) {
+        return null;
+    }
+
+    @Override
+    public Object visitConstant(@NotNull Constant term) {
+        return term.getValue();
+    }
+
+    @Override
+    public Object visitInteger(@NotNull Integer term) {
+        return term.getValue().toLong();
+    }
+
+    @Override
+    public Object visitReal(@NotNull Real term) {
+        return term.getValue().toDouble();
+    }
+
+    @Override
+    public Object visitStruct(@NotNull Struct term) {
+        return Map.of(term.getFunctor(), term.getArgAt(0).accept(this));
+    }
+
+    @Override
+    public Object visitList(@NotNull List term) {
+        if (term.toList().stream().allMatch(Term::isStruct)) {
+            var map = new LinkedHashMap<String, Object>();
+            term.toList().stream()
+                    .map(Term::asStruct)
+                    .filter(Objects::nonNull)
+                    .forEach(s -> map.put(s.getFunctor(), s.getArgAt(0).accept(this)));
+            return map;
+        } else {
+            return term.toList().stream().map(t -> t.accept(this)).collect(Collectors.toCollection(ArrayList::new));
+        }
+    }
+
+    @Override
+    public Object visitAtom(@NotNull Atom term) {
+        return term.getValue();
+    }
+}
+

+ 13 - 0
frameworks/Prolog/tuProlog/tuprolog.dockerfile

@@ -0,0 +1,13 @@
+FROM maven:3-openjdk-16 AS builder
+WORKDIR /runner
+COPY pom.xml pom.xml
+RUN mvn dependency:go-offline -B
+COPY src src
+RUN mvn package -q
+
+FROM adoptopenjdk:16-jre-hotspot
+COPY --from=builder /runner/target/tuprolog-web-runner-1.0-SNAPSHOT-jar-with-dependencies.jar /runner.jar
+COPY app /app
+EXPOSE 8080
+
+CMD [ "java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "/runner.jar", "/app/application.prolog" ]