├── .gitignore ├── 3rd_party_license.md ├── LICENSE.md ├── README.md ├── build_all.sh ├── ci.hocon ├── clean_all.sh ├── fastr_javaui ├── README.md ├── build.sh ├── clean.sh ├── run.sh ├── screen.png ├── src │ └── main │ │ └── java │ │ └── com │ │ └── oracle │ │ └── truffle │ │ └── r │ │ └── fastrjavaui │ │ ├── FastRJavaCmd.java │ │ └── FastRJavaUI.java └── test.sh ├── fastr_llvm_debug_demo ├── .vscode │ └── launch.json ├── Dockerfile ├── README.md ├── gibbs │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ ├── RcppExports.R │ │ └── gibbs.R │ ├── man │ │ └── gibbs-package.Rd │ └── src │ │ ├── RcppExports.cpp │ │ └── gibbs.cpp └── simple │ ├── lapplyNative.R │ └── lapplyNative.c ├── fastr_node ├── README.md ├── build.sh ├── clean.sh ├── model.r ├── package.json ├── public │ ├── index.html │ ├── script.js │ └── vendor │ │ └── jquery.min.js ├── run.sh ├── server.js ├── test.sh ├── tools-ce.sh └── tools.sh ├── fastr_scalar ├── README.md ├── gameoflife.R ├── run.sh └── screen.png ├── install_components.sh ├── r_java_bench ├── README.md ├── fastr_interop_bench.R ├── java.R ├── r_java_bench.R ├── results.png ├── test.R └── test.sh ├── r_java_embedding ├── README.md ├── build.sh ├── clean.sh ├── expected.out ├── package.json ├── run.sh ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── oracle │ │ │ └── truffle │ │ │ └── r │ │ │ ├── fastrembedding │ │ │ └── FastREmbeddingDemo.java │ │ │ └── fastrj │ │ │ ├── BrexitHandler.R │ │ │ ├── BrexitHandler.java │ │ │ ├── Dplyr.java │ │ │ ├── DplyrQueryBuilder.java │ │ │ ├── FastR.java │ │ │ ├── FastREmbeddingDemo.java │ │ │ ├── FastRJavaUI.java │ │ │ ├── GraalVM.java │ │ │ ├── IrisHandler.R │ │ │ ├── IrisHandler.java │ │ │ ├── PlotJPanel.java │ │ │ └── RBundle.java │ │ ├── js │ │ └── server.js │ │ └── resources │ │ ├── msleep_ggplot2.csv │ │ └── sampleBundle.R └── test.sh ├── shared_domain_logic ├── Gemfile ├── Gemfile.lock ├── README.md ├── THIRD_PARTY_LICENSES.TXT ├── app.rb ├── build.sh ├── public │ ├── index.html │ ├── people.html │ └── person.js ├── run.sh └── test.sh ├── test_all.sh └── weather_predictor ├── README.md ├── build.sh ├── clean.sh ├── java └── com │ └── oracle │ └── graalvm │ └── demo │ └── weather │ ├── City.java │ └── CityService.java ├── java_options ├── package.json ├── public ├── index.html ├── js │ ├── jquery-3.2.1.min.js │ └── script.js └── script.js ├── run.sh ├── test.sh ├── tools-ce.sh ├── tools.sh ├── weatherInit.rb ├── weatherModel.r └── weatherServer.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | fastr_javaui/bin 3 | fastr_javaui/test.png 4 | fastr_node/node_modules/ 5 | weather_predictor/node_modules/ 6 | weather_predictor/openweather/ 7 | weather_predictor/rlang/ 8 | weather_predictor/bin/ 9 | fastr_rJava/RJavaBench.java 10 | fastr_rJava/RJavaBench.class 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraalVM Examples 2 | 3 | A collection of examples and use-cases for the GraalVM and FastR. 4 | 5 | [GraalVM](http://graalvm.org) is a universal virtual machine for running applications written in JavaScript, 6 | Python 3, Ruby, R, JVM-based languages like Java, Scala, Kotlin, and LLVM-based languages 7 | such as C and C++. 8 | 9 | FastR is a GraalVM based implementation of the R programming language, that provides significant improvements in the performance of R code, 10 | the embedding of the R execution engine into Java applications, and the ability to interface with other GraalVM and JVM languages including Python, Java, and Scala. 11 | FastR is also able to utilize the [tooling support](https://medium.com/graalvm/analyzing-the-heap-of-graalvm-polyglot-applications-b9963e68a6a) provided by the 12 | [GraalVM ecosystem](https://medium.com/graalvm/graalvm-ten-things-12d9111f307d). 13 | 14 | * [FastR Java UI](./fastr_javaui/README.md) is a Java based Swing desktop UI application showing visualization interactively generated an by R script. 15 | * [rJava Benchmark](./r_java_bench) shows how fast rJava can be on FastR (spoiler: orders of magnitude faster). 16 | * [FastR Embedding](./r_java_embedding) show how to embed FastR into Java applications and pass Java objects to R scripts like if they were native R objects (e.g. R data frame). 17 | * [Weather Predictor](./weather_predictor/README.md) is an application that performs temperature prediction using Ruby, R and Node.js. 18 | * [FastR Scalar](./fastr_scalar/README.md) is a simple, straightforward implementation of "Conway's Game of Life" written in R. 19 | * [Node.js & FastR](./fastr_node/README.md) is a Node.js web server showing visualization computed and generated in FastR. 20 | 21 | ## Setup 22 | 23 | In order to run the examples, the latest GraalVM must be installed. 24 | It can be downloaded from the [GraalVM homepage](http://www.graalvm.org/downloads/). 25 | The examples work on both the Community and Enterprise edition of GraalVM. 26 | 27 | Once downloaded, extract the archive, set the `GRAALVM_DIR` environment variable to point to the graalvm directory, 28 | and install additional languages using [`./install_components.sh`](install_components.sh). 29 | 30 | ## Further information 31 | 32 | * [GraalVM homepage](http://graalvm.org) 33 | * [FastR reference manual](http://www.graalvm.org/docs/reference-manual/languages/r/) 34 | * [FastR on Github](https://github.com/oracle/fastr) 35 | 36 | ## License 37 | 38 | All the examples are licensed under the [GPLv3 license](https://www.gnu.org/licenses/gpl-3.0). 39 | 40 | ## Troubleshooting 41 | 42 | A typical problem is proxy set-up: verify that you have the `http_proxy`, `https_proxy`, and `no_proxy` environment variables set properly. 43 | 44 | 45 | -------------------------------------------------------------------------------- /build_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | 7 | # Resolve the location of this script 8 | source="${BASH_SOURCE[0]}" 9 | while [ -h "$source" ] ; do 10 | prev_source="$source" 11 | source="$(readlink "$source")"; 12 | if [[ "$source" != /* ]]; then 13 | # if the link was relative, it was relative to where it came from 14 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 15 | source="$dir/$source" 16 | fi 17 | done 18 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 19 | 20 | set -x 21 | 22 | ${dir}/weather_predictor/build.sh 23 | ${dir}/fastr_javaui/build.sh 24 | ${dir}/fastr_node/build.sh 25 | ${dir}/r_java_embedding/build.sh 26 | ${dir}/shared_domain_logic/build.sh 27 | -------------------------------------------------------------------------------- /ci.hocon: -------------------------------------------------------------------------------- 1 | overlay: e2f798b03a92f88a796242821c3a57536e362789 2 | -------------------------------------------------------------------------------- /clean_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | 7 | # Resolve the location of this script 8 | source="${BASH_SOURCE[0]}" 9 | while [ -h "$source" ] ; do 10 | prev_source="$source" 11 | source="$(readlink "$source")"; 12 | if [[ "$source" != /* ]]; then 13 | # if the link was relative, it was relative to where it came from 14 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 15 | source="$dir/$source" 16 | fi 17 | done 18 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 19 | 20 | set -x 21 | 22 | ${dir}/weather_predictor/clean.sh 23 | ${dir}/fastr_javaui/clean.sh 24 | ${dir}/fastr_node/clean.sh 25 | ${dir}/r_java_embedding/clean.sh 26 | -------------------------------------------------------------------------------- /fastr_javaui/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![Screenshot](screen.png) 3 | 4 | # R's graphical output in Java based desktop application 5 | 6 | This demo shows an interactive Java based desktop application that displays k-means clustering on the iris data set. 7 | The user can choose variables for the x and y axes and the number of clusters. 8 | The UI is updated accordingly in real time. 9 | The clustering and plotting is done in R using `kmeans` function from the stats package and `xyplot` function from the lattice package. 10 | 11 | Under the hood, FastR emulates the grid and grDevices packages purely in Java and is capable of drawing directly to Graphics2D context without the typical cost of crossing language boundaries. 12 | 13 | 14 | ## Setup 15 | 16 | Follow the instructions from the top level [README](../README.md) to install and setup GraalVM 17 | and then execute the `build.sh` script. 18 | 19 | 20 | ## Run 21 | 22 | Execute the `run.sh` script. 23 | -------------------------------------------------------------------------------- /fastr_javaui/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | echo "Compiling the Java sources" 24 | mkdir -p ${dir}/bin 25 | ${GRAALVM_DIR}/bin/javac -d ${dir}/bin ${dir}/src/main/java/com/oracle/truffle/r/fastrjavaui/*.java 26 | -------------------------------------------------------------------------------- /fastr_javaui/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | 7 | # Resolve the location of this script 8 | source="${BASH_SOURCE[0]}" 9 | while [ -h "$source" ] ; do 10 | prev_source="$source" 11 | source="$(readlink "$source")"; 12 | if [[ "$source" != /* ]]; then 13 | # if the link was relative, it was relative to where it came from 14 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 15 | source="$dir/$source" 16 | fi 17 | done 18 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 19 | 20 | rm -rf ${dir}/bin 21 | rm -f ${dir}/test.png 22 | -------------------------------------------------------------------------------- /fastr_javaui/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | ${GRAALVM_DIR}/bin/java -cp ${dir}/bin com.oracle.truffle.r.fastrjavaui.FastRJavaUI 24 | -------------------------------------------------------------------------------- /fastr_javaui/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graalvm/fastr-examples/be8a58faac569e5e94b062bd44f7b89331447f81/fastr_javaui/screen.png -------------------------------------------------------------------------------- /fastr_javaui/src/main/java/com/oracle/truffle/r/fastrjavaui/FastRJavaCmd.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | 6 | package com.oracle.truffle.r.fastrjavaui; 7 | 8 | import static java.awt.image.BufferedImage.TYPE_INT_RGB; 9 | 10 | import java.awt.Color; 11 | import java.awt.Graphics2D; 12 | import java.awt.image.BufferedImage; 13 | import java.io.File; 14 | import java.io.FileNotFoundException; 15 | import java.io.IOException; 16 | import java.nio.file.Files; 17 | import java.nio.file.Paths; 18 | 19 | import javax.imageio.ImageIO; 20 | 21 | import org.graalvm.polyglot.Context; 22 | import org.graalvm.polyglot.Value; 23 | 24 | public class FastRJavaCmd { 25 | private static final int WIDTH = 700; 26 | private static final int HEIGHT = 500; 27 | 28 | public static void main(String[] args) { 29 | Context context = Context.newBuilder("R").allowAllAccess(true).build(); 30 | // This R function opens FastR graphics device passing it Graphics2D object, 31 | // then it plots the graph and closes the device 32 | String src = "library(grid); library(lattice); " + 33 | "function(g, w, h, clustersCount, x, y) { " + 34 | " grDevices:::awt(w, h, g);" + 35 | " iris$cluster <- factor(kmeans(iris[, c(y, x)], clustersCount)$cluster);" + 36 | " print(xyplot(as.formula(paste0(y,'~',x)), data=iris, groups=cluster, pch=20, cex=3));" + 37 | " dev.off();" + 38 | " NULL;" + 39 | "}"; 40 | Value showPlot = context.eval("R", src); 41 | 42 | // Instead of drawing to a component, we use BufferedImage for headless testing 43 | // Note: one can achieve this with "png" built-in directly in R, 44 | // this is only example of what can be done 45 | BufferedImage image = new BufferedImage(WIDTH, HEIGHT, TYPE_INT_RGB); 46 | Graphics2D graphics = (Graphics2D) image.getGraphics(); 47 | graphics.setBackground(new Color(255, 255, 255)); 48 | graphics.clearRect(0, 0, WIDTH, HEIGHT); 49 | 50 | // The MAGIC happens HERE: we invoke R plotting code and pass it graphics object 51 | showPlot.execute(graphics, WIDTH, HEIGHT, 4, "Sepal.Width", "Sepal.Length"); 52 | 53 | // Save the image to file 54 | String dest = System.getProperty("fastrjavaui.dest", "test.png"); 55 | try { 56 | ImageIO.write(image, "png", new File(dest)); 57 | } catch (IOException e) { 58 | e.printStackTrace(); 59 | } 60 | System.out.println("SUCCESS"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /fastr_javaui/src/main/java/com/oracle/truffle/r/fastrjavaui/FastRJavaUI.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | package com.oracle.truffle.r.fastrjavaui; 6 | 7 | import java.awt.BorderLayout; 8 | import java.awt.Container; 9 | import java.awt.Dimension; 10 | import java.awt.FlowLayout; 11 | import java.awt.Graphics; 12 | import java.awt.Graphics2D; 13 | import java.awt.event.ActionListener; 14 | import java.util.function.Supplier; 15 | 16 | import javax.swing.JComboBox; 17 | import javax.swing.JFrame; 18 | import javax.swing.JLabel; 19 | import javax.swing.JPanel; 20 | import javax.swing.WindowConstants; 21 | import javax.swing.border.EmptyBorder; 22 | 23 | import org.graalvm.polyglot.Context; 24 | import org.graalvm.polyglot.Value; 25 | 26 | public class FastRJavaUI { 27 | static final class PlotParams { 28 | final int clustersCount; 29 | final String xVar; 30 | final String yVar; 31 | 32 | PlotParams(int clustersCount, String xVar, String yVar) { 33 | this.clustersCount = clustersCount; 34 | this.xVar = xVar; 35 | this.yVar = yVar; 36 | } 37 | } 38 | 39 | static final class PlotJPanel extends JPanel { 40 | private final Supplier paramsSupplier; 41 | private Context context = null; 42 | private Value showPlot = null; 43 | 44 | PlotJPanel(Supplier paramsSupplier) { 45 | this.paramsSupplier = paramsSupplier; 46 | } 47 | 48 | @Override 49 | public void paint(Graphics g) { 50 | super.paint(g); 51 | if (context == null) { 52 | context = Context.newBuilder("R").allowAllAccess(true).build(); 53 | // This R function opens FastR graphics device passing it Graphics2D object, 54 | // then it plots the graph and closes the device 55 | String src = "library(grid); library(lattice); " + 56 | "function(g, w, h, clustersCount, x, y) { " + 57 | " grDevices:::awt(w, h, g);" + 58 | " iris$cluster <- factor(kmeans(iris[, c(y, x)], clustersCount)$cluster);" + 59 | " print(xyplot(as.formula(paste0(y,'~',x)), data=iris, groups=cluster, pch=20, cex=3));" + 60 | " dev.off();" + 61 | " NULL;" + 62 | "}"; 63 | showPlot = context.eval("R", src); 64 | } 65 | PlotParams params = paramsSupplier.get(); 66 | // The MAGIC happens HERE: we invoke R plotting code and pass it graphics object 67 | showPlot.execute((Graphics2D) g, getWidth(), getHeight(), params.clustersCount, params.xVar, params.yVar); 68 | } 69 | } 70 | 71 | //Create and set up the window -- this is standard Java/Swing 72 | private static void createAndShowGUI() { 73 | JFrame frame = new JFrame("Hello World to R from Java"); 74 | frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 75 | frame.setPreferredSize(new Dimension(750, 500)); 76 | 77 | JComboBox clustersCombo = new JComboBox<>(new Integer[]{2, 3, 4, 5, 6, 7}); 78 | clustersCombo.setSelectedIndex(2); 79 | String[] variables = {"Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"}; 80 | JComboBox xAxisCombo = new JComboBox<>(variables); 81 | JComboBox yAxisCombo = new JComboBox<>(variables); 82 | yAxisCombo.setSelectedIndex(1); 83 | 84 | JPanel plot = new PlotJPanel(() -> 85 | new PlotParams( 86 | (Integer) clustersCombo.getSelectedItem(), 87 | (String) xAxisCombo.getSelectedItem(), 88 | (String) yAxisCombo.getSelectedItem())); 89 | ActionListener updatePlot = e -> plot.repaint(); 90 | clustersCombo.addActionListener(updatePlot); 91 | xAxisCombo.addActionListener(updatePlot); 92 | yAxisCombo.addActionListener(updatePlot); 93 | 94 | JPanel options = new JPanel(); 95 | options.setLayout(new FlowLayout(FlowLayout.CENTER)); 96 | options.add(new JLabel("X Variable: ")); 97 | options.add(xAxisCombo); 98 | options.add(new JLabel("Y Variable: ")); 99 | options.add(yAxisCombo); 100 | options.add(new JLabel("Clusters count: ")); 101 | options.add(clustersCombo); 102 | xAxisCombo.setBorder(new EmptyBorder(0, 0, 0, 40)); 103 | yAxisCombo.setBorder(new EmptyBorder(0, 0, 0, 40)); 104 | clustersCombo.setBorder(new EmptyBorder(0, 0, 0, 40)); 105 | 106 | frame.setLayout(new BorderLayout(20, 20)); 107 | Container pane = frame.getContentPane(); 108 | pane.add(options, BorderLayout.PAGE_START); 109 | pane.add(plot, BorderLayout.CENTER); 110 | 111 | frame.pack(); 112 | frame.setVisible(true); 113 | } 114 | 115 | // We call to R through this interface. 116 | @FunctionalInterface 117 | interface ShowPlot { 118 | void show(Graphics2D graphics2D, int width, int height, int clustersCount, String x, String y); 119 | } 120 | 121 | public static void main(String[] args) throws Exception { 122 | javax.swing.SwingUtilities.invokeLater(() -> createAndShowGUI()); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /fastr_javaui/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | set -o xtrace 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | rm -f ${dir}/test.png 24 | echo Testing GraalVM fastr_javaui example 25 | if ! ${GRAALVM_DIR}/bin/java -cp ${dir}/bin -Dfastrjavaui.dest=${dir}/test.png com.oracle.truffle.r.fastrjavaui.FastRJavaCmd | grep "SUCCESS" > /dev/null; then 26 | echo "expected output not found" 27 | exit 1 28 | fi 29 | if [ ! -f ${dir}/test.png ]; then 30 | echo "expected file not generated" 31 | exit 1 32 | fi 33 | echo DONE 34 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "attach", 10 | "name": "Attach", 11 | "port": 9229 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/Dockerfile: -------------------------------------------------------------------------------- 1 | # Based on https://github.com/graalvm/fastr#building-fastr-from-source 2 | FROM openjdk:9-jdk 3 | 4 | RUN sed -i "s/deb.debian.org/cdn-fastly.deb.debian.org/" /etc/apt/sources.list \ 5 | && sed -i "s/security.debian.org/cdn-fastly.debian.org\/debian-security/" /etc/apt/sources.list \ 6 | && apt-get update \ 7 | && apt-get install -y --no-install-recommends \ 8 | build-essential \ 9 | gfortran \ 10 | libpcre3-dev \ 11 | libreadline-dev \ 12 | zlib1g-dev \ 13 | libbz2-dev \ 14 | liblzma-dev \ 15 | libcurl4-openssl-dev \ 16 | ed \ 17 | libmpc-dev \ 18 | libssl-dev \ 19 | && ldconfig 20 | 21 | WORKDIR /jdk 22 | RUN wget https://github.com/graalvm/openjdk8-jvmci-builder/releases/download/jvmci-19.2-b02/openjdk-8u222-jvmci-19.2-b02-linux-amd64.tar.gz \ 23 | && tar -xzf openjdk-8u222-jvmci-19.2-b02-linux-amd64.tar.gz 24 | 25 | ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu/ 26 | 27 | ENV FASTR_HOME=/fastr 28 | ENV MX_HOME=/usr/mx 29 | ENV PATH=$MX_HOME:/graal/sulong/mxbuild/SULONG_LLVM_ORG/bin:$PATH 30 | ENV JAVA_HOME=/jdk/openjdk1.8.0_222-jvmci-19.2-b02 31 | 32 | # See https://github.com/oracle/graal/blob/master/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java 33 | #ENV JVMCI_VERSION_CHECK=ignore 34 | 35 | WORKDIR $FASTR_HOME 36 | 37 | # based on https://github.com/oracle/fastr#building-fastr-from-source 38 | RUN git clone --depth 1 -b master https://github.com/graalvm/mx.git $MX_HOME 39 | RUN git clone --depth 1 https://github.com/oracle/fastr $FASTR_HOME 40 | RUN mx sforceimports 41 | WORKDIR /graal/sulong 42 | RUN mx build --projects SULONG_LLVM_ORG 43 | RUN mx build 44 | WORKDIR $FASTR_HOME 45 | RUN mx build 46 | 47 | # https://github.com/oracle/fastr/issues/11#issuecomment-389490445 48 | WORKDIR /graal/compiler 49 | RUN mx build 50 | 51 | WORKDIR /graal/tools 52 | RUN mx build 53 | 54 | ARG VCS_URL 55 | ARG VCS_REF 56 | ARG BUILD_DATE 57 | ARG GNUR_VERSION=3.5.1 58 | LABEL org.label-schema.license="https://raw.githubusercontent.com/graalvm/fastr/master/LICENSE" \ 59 | org.label-schema.vendor="FastR project team" \ 60 | org.label-schema.name="FastR" \ 61 | org.label-schema.description="FastR is an implementation of the R Language in Java atop Truffle, a framework for building self-optimizing AST interpreters." \ 62 | org.label-schema.vcs-url=$VCS_URL \ 63 | org.label-schema.vcs-ref=$VCS_REF \ 64 | org.label-schema.build-date=$BUILD_DATE \ 65 | org.fastr.version="devel" \ 66 | org.gnur.version=$GNUR_VERSION \ 67 | org.label-schema.schema-version="rc1" \ 68 | maintainer="Zbyněk Šlajchrt " 69 | 70 | WORKDIR $FASTR_HOME 71 | ENV LANG=en_US.UTF-8 72 | ENV LD_LIBRARY_PATH=/graal/sulong/mxbuild/SULONG_LLVM_ORG/lib 73 | ENV PATH=$FASTR_HOME/bin:$PATH 74 | ENV DEFAULT_DYNAMIC_IMPORTS=graal/compiler,graal/tools 75 | 76 | RUN mv etc/Makevars.site.debug etc/Makevars.site 77 | 78 | WORKDIR $FASTR_HOME/rpkgs 79 | RUN wget https://cran.r-project.org/src/contrib/Archive/Rcpp/Rcpp_1.0.0.tar.gz \ 80 | && tar -xzf Rcpp_1.0.0.tar.gz 81 | RUN R CMD INSTALL Rcpp 82 | 83 | COPY . /fastr_llvm_debug_demo 84 | 85 | ENV MX_R_GLOBAL_ARGS="--cp-sfx /graal/tools/mxbuild/dists/jdk1.8/truffle-profiler.jar:/graal/tools/mxbuild/dists/jdk1.8/chromeinspector.jar" 86 | 87 | EXPOSE 9229 88 | 89 | WORKDIR / 90 | 91 | # ENTRYPOINT [ "mx", "--dynamicimports", "graal/compiler", "R" ] 92 | # enable compilation logs with mx --dynamicimport graal/compiler --J "@-Dgraal.TraceTruffleCompilation=true" R 93 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/README.md: -------------------------------------------------------------------------------- 1 | # Mixed Interactive Debugging of R and Native Code with FastR 2 | 3 | ## Prerequisites 4 | 5 | ### Visual Studio Code 6 | 7 | Visit the Visual Studio Code [download page](https://code.visualstudio.com/download) and download the installer suiting your platform. 8 | 9 | ### Open Demo Workspace 10 | 11 | Add the `fastr_llvm_debug_demo` folder to the workspace via the `File` menu or clicking the Add Folder button in the Explorer. The folder 12 | already contains the debugger configuration. 13 | 14 | ### VSC R Plugin 15 | 16 | Select the `Preferences | Extensions` menu and type `R` in the search box on the top of the `Extensions` panel. 17 | The search result should include the R plugin by Yuki Ueda. Select it and click the `Install` button situated 18 | just below the caption of the plugin's description page. 19 | 20 | ### FastR 21 | 22 | For the sake of simplicity, there is a Docker image having all necessary components preinstalled. Pull the image using the following command. 23 | 24 | ``` 25 | docker pull zslajchrt/fastr_llvm_debug_demo 26 | ``` 27 | 28 | Then execute the image by 29 | 30 | ``` 31 | docker run -p 9229:9229 -it zslajchrt/fastr_llvm_debug_demo bash 32 | ``` 33 | 34 | and launch FastR by entering `R` from the bash command line. 35 | 36 | ## Running GraalVM Examples 37 | 38 | ### Building a simple native library 39 | 40 | ``` 41 | cd /fastr_llvm_debug_demo/simple/ 42 | R CMD SHLIB -o lapplyNative.so lapplyNative.c 43 | ``` 44 | 45 | ### Using the simple native library in R 46 | 47 | Launch FastR with the LLVM backend and with the right options that activate the GraalVM debugger: 48 | 49 | ``` 50 | R --inspect=0.0.0.0:9229 --inspect.Secure=false --R.BackEndLLVM --R.DebugLLVMLibs 51 | ``` 52 | 53 | Then launch Visual Studio Code and press F5 to attach to the GraalVM debugger. Return to FastR 54 | and run the following snippet: 55 | 56 | ``` 57 | dyn.load("/fastr_llvm_debug_demo/simple/lapplyNative.so") 58 | source("lapplyNative.R") 59 | x <- list(a = 1:5, b = rnorm(10)) 60 | lapplyNative(x, sum) 61 | ``` 62 | 63 | Switch to VSC and locate `lapplyNative.c` in the Loaded Scripts panel. Then toggle a breakpoint 64 | there and re-run `lapplyNative(x, sum)`. 65 | 66 | ### Installing a package utilizing Rcpp 67 | 68 | ``` 69 | cd /fastr_llvm_debug_demo 70 | R CMD INSTALL gibbs 71 | ``` 72 | 73 | ### Debugging a package utilizing Rcpp 74 | 75 | ``` 76 | R --inspect=0.0.0.0:9229 --inspect.Secure=false --R.BackEndLLVM --R.DebugLLVMLibs 77 | ``` 78 | 79 | ``` 80 | library(gibbs) 81 | gibbs_cpp(100, 10) 82 | ``` 83 | 84 | Locate `gibbs.cpp` in VSC's Loaded Scripts panel, toggle a breakpoint there and re-run `gibbs_cpp(100, 10)`. 85 | Debugger should stop at the breakpoint. 86 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/gibbs/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: gibbs 2 | Type: Package 3 | Title: Gibbs filter 4 | Version: 1.0 5 | Date: 2019-07-01 6 | Author: Zbynek Slajchrt 7 | Maintainer: Zbynek Slajchrt 8 | Description: This package is used to demonstrate the capabilities 9 | of GraalVM debugger. 10 | License: GPL (>= 2) 11 | Imports: Rcpp (>= 1.0.0) 12 | LinkingTo: Rcpp 13 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/gibbs/NAMESPACE: -------------------------------------------------------------------------------- 1 | useDynLib(gibbs, .registration=TRUE) 2 | exportPattern("^[[:alpha:]]+") 3 | importFrom(Rcpp, evalCpp) 4 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/gibbs/R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | gibbs_cpp <- function(N, thin) { 5 | .Call(`_gibbs_gibbs_cpp`, N, thin) 6 | } 7 | 8 | rcpp_hello_world <- function() { 9 | .Call(`_gibbs_rcpp_hello_world`) 10 | } 11 | 12 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/gibbs/R/gibbs.R: -------------------------------------------------------------------------------- 1 | # 2 | # This code is copied from the Advanced R tutorial by Hadley Wickham. 3 | # The original code can be found on http://adv-r.had.co.nz/Rcpp.html#rcpp-package 4 | # 5 | 6 | gibbs_r <- function(N, thin) { 7 | mat <- matrix(nrow = N, ncol = 2) 8 | x <- y <- 0 9 | 10 | for (i in 1:N) { 11 | for (j in 1:thin) { 12 | x <- rgamma(1, 3, y * y + 4) 13 | y <- rnorm(1, 1 / (x + 1), 1 / sqrt(2 * (x + 1))) 14 | } 15 | mat[i, ] <- c(x, y) 16 | } 17 | mat 18 | } 19 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/gibbs/man/gibbs-package.Rd: -------------------------------------------------------------------------------- 1 | \name{gibbs-package} 2 | \alias{gibbs-package} 3 | \alias{gibbs} 4 | \docType{package} 5 | \title{ 6 | A short title line describing what the package does 7 | } 8 | \description{ 9 | A more detailed description of what the package does. A length 10 | of about one to five lines is recommended. 11 | } 12 | \details{ 13 | This section should provide a more detailed overview of how to use the 14 | package, including the most important functions. 15 | } 16 | \author{ 17 | Your Name, email optional. 18 | 19 | Maintainer: Your Name 20 | } 21 | \references{ 22 | This optional section can contain literature or other references for 23 | background information. 24 | } 25 | \keyword{ package } 26 | \seealso{ 27 | Optional links to other man pages 28 | } 29 | \examples{ 30 | \dontrun{ 31 | ## Optional simple examples of the most important functions 32 | ## These can be in \dontrun{} and \donttest{} blocks. 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/gibbs/src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | // gibbs_cpp 9 | NumericMatrix gibbs_cpp(int N, int thin); 10 | RcppExport SEXP _gibbs_gibbs_cpp(SEXP NSEXP, SEXP thinSEXP) { 11 | BEGIN_RCPP 12 | Rcpp::RObject rcpp_result_gen; 13 | Rcpp::RNGScope rcpp_rngScope_gen; 14 | Rcpp::traits::input_parameter< int >::type N(NSEXP); 15 | Rcpp::traits::input_parameter< int >::type thin(thinSEXP); 16 | rcpp_result_gen = Rcpp::wrap(gibbs_cpp(N, thin)); 17 | return rcpp_result_gen; 18 | END_RCPP 19 | } 20 | 21 | static const R_CallMethodDef CallEntries[] = { 22 | {"_gibbs_gibbs_cpp", (DL_FUNC) &_gibbs_gibbs_cpp, 2}, 23 | {NULL, NULL, 0} 24 | }; 25 | 26 | RcppExport void R_init_gibbs(DllInfo *dll) { 27 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 28 | R_useDynamicSymbols(dll, FALSE); 29 | } 30 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/gibbs/src/gibbs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace Rcpp; 3 | 4 | // [[Rcpp::export]] 5 | NumericMatrix gibbs_cpp(int N, int thin) { 6 | NumericMatrix mat(N, 2); 7 | double x = 0, y = 0; 8 | 9 | for(int i = 0; i < N; i++) { 10 | for(int j = 0; j < thin; j++) { 11 | x = rgamma(1, 3, 1 / (y * y + 4))[0]; 12 | y = rnorm(1, 1 / (x + 1), 1 / sqrt(2 * (x + 1)))[0]; 13 | } 14 | mat(i, 0) = x; 15 | mat(i, 1) = y; 16 | } 17 | 18 | return(mat); 19 | } 20 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/simple/lapplyNative.R: -------------------------------------------------------------------------------- 1 | populateIntVector <- function(n) { 2 | .Call("populateIntVector", as.integer(n)) 3 | } 4 | 5 | lapplyNative <- function (x, fun, env = new.env()) { 6 | .Call("lapplyNative", x, fun, env) 7 | } 8 | -------------------------------------------------------------------------------- /fastr_llvm_debug_demo/simple/lapplyNative.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | SEXP lapplyNative(SEXP list, SEXP fn, SEXP rho) { 5 | int n = length(list); 6 | SEXP R_fcall, ans; 7 | 8 | R_fcall = PROTECT(lang2(fn, R_NilValue)); 9 | ans = PROTECT(allocVector(VECSXP, n)); 10 | for(int i = 0; i < n; i++) { 11 | SETCADR(R_fcall, VECTOR_ELT(list, i)); 12 | SET_VECTOR_ELT(ans, i, eval(R_fcall, rho)); 13 | } 14 | setAttrib(ans, R_NamesSymbol, 15 | getAttrib(list, R_NamesSymbol)); 16 | UNPROTECT(2); 17 | return ans; 18 | } 19 | -------------------------------------------------------------------------------- /fastr_node/README.md: -------------------------------------------------------------------------------- 1 | # FastR Node.js interop example 2 | 3 | Demo inspired by Shiny R web applications framework [examples](https://shiny.rstudio.com/gallery/kmeans-example.html). 4 | 5 | 6 | ## Setup 7 | 8 | Download the latest GraalVM image from the [Oracle Technology Network](http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html). 9 | Extract the archive and set the `GRAALVM_DIR` environment variable to point to the graalvm directory. 10 | 11 | Then, execute the `build.sh` script. 12 | 13 | A typical problem is proxy set-up: verify that you have the `http_proxy`, `https_proxy`, and `no_proxy` environment variables set properly. 14 | 15 | 16 | ## Run 17 | 18 | Execute the `run.sh` script and open your browser at `http://localhost:12837`. 19 | -------------------------------------------------------------------------------- /fastr_node/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | # Install expressjs 24 | echo "Running npm install" 25 | ${GRAALVM_DIR}/bin/npm --prefix ${dir} install ${dir} 26 | -------------------------------------------------------------------------------- /fastr_node/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | rm -rf ${dir}/node_modules 22 | -------------------------------------------------------------------------------- /fastr_node/model.r: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 2 | # This file is made available under version 3 of the GNU General Public License. 3 | 4 | library(lattice) 5 | 6 | plotkmeans <- function(x, y, clusters) { 7 | svg(width=10, height=8) 8 | data <- kmeans(iris[, c(y, x)], as.integer(clusters)) 9 | iris$cluster <- factor(data$cluster) 10 | print(xyplot(as.formula(paste0(y,'~',x)), data=iris, groups=cluster, pch=20, cex=3)) 11 | grDevices:::svg.off() 12 | } 13 | 14 | plotcars <- function(x, y, z) { 15 | svg(width=10, height=8) 16 | mtcars$gear.f<-factor(mtcars$gear,levels=c(3,4,5), labels=c("3gears","4gears","5gears")) 17 | mtcars$cyl.f <-factor(mtcars$cyl,levels=c(4,6,8), labels=c("4cyl","6cyl","8cyl")) 18 | print(cloud(as.formula(paste0(x,'~',y,'*',z)), main="3D Scatterplot generated in R", data=mtcars)) 19 | grDevices:::svg.off() 20 | } 21 | 22 | model <- lm(weight~height, data=women) 23 | 24 | plotheightweitgh <- function(x, y, z) { 25 | svg(width=10, height=8) 26 | print(xyplot(weight ~ height, data = women, 27 | panel = function(x, y) { 28 | panel.xyplot(x, y, cex=2, pch=19) 29 | panel.abline(model) 30 | })); 31 | grDevices:::svg.off() 32 | } 33 | 34 | predictweight <- function(height) { 35 | predict(model, as.data.frame(list(height=height))) 36 | } 37 | 38 | export('plotkmeans', plotkmeans) 39 | export('plotcars', plotcars) 40 | export('plotheightweight', plotheightweitgh) 41 | export('predictweight', predictweight) 42 | -------------------------------------------------------------------------------- /fastr_node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastr_nodejs", 3 | "version": "1.0.0", 4 | "description": "GraalVM interoperability demo: copy of a Shiny example that scales!", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "GraalVM team", 10 | "license": "Universal Permissive License (UPL)", 11 | "dependencies": { 12 | "express": "^4.15.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fastr_node/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | GraalVM ala Shiny demo 15 | 16 | 17 |
18 |

Oracle Labs   GraalVM demo

19 |
20 | 39 | 40 |
41 |
42 |
43 |
44 |
45 | 46 | 52 |
53 |
54 | 55 | 61 |
62 |
63 | 64 | 70 |
71 |
72 |
73 |
74 |

Visualization of k-means clustering algorithm. Both the clusters computation 75 | and the visualization are generated by FastR. This sample was inspired by similar demo used by Shiny web application framework for R. 76 | In this case, the web part is implemented in Node.js

77 |
78 |
79 |
80 |
81 | 82 | 134 | 135 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /fastr_node/public/script.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | $(document).ready(function() { 6 | // navigation between pages: 7 | $('.navbar-nav a').click(function(e) { 8 | $('.page').hide(); 9 | $('.navbar-nav .active').removeClass('active') 10 | $('#' + $(this).data('page')).show(); 11 | $(this).parent().addClass('active') 12 | e.preventDefault(); 13 | return false; 14 | }); 15 | 16 | // data loading 17 | var refresh = function(page) { 18 | var query = {}; 19 | let inputs = page.find('.plot-form .input').each((idx, e) => query[$(e).attr('id')] = $(e).val()); 20 | $.get('http://localhost:12837/' + page.attr('id'), query, function(data) { 21 | page.find('.plot').html(data); 22 | }); 23 | } 24 | 25 | refresh($('#kmeans')); 26 | refresh($('#cars')); 27 | refresh($('#lm')); 28 | 29 | $('.input').change(function(e) { 30 | refresh($(this).parents('.page:first')); 31 | e.preventDefault(); 32 | return false; 33 | }); 34 | 35 | // linear regression 36 | $('#predict-button').click((e) => { 37 | let height = $('#height').val(); 38 | $('#prediction-text').show(2000); 39 | $.get('http://localhost:12837/lm/predict/', {height: height}, function(data) { 40 | $('#prediction').html(data); 41 | }); 42 | e.preventDefault(); 43 | return false; 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /fastr_node/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | # Runs the demo without any tools enabled and printing all exceptions to terminal 24 | ${GRAALVM_DIR}/bin/node ${GRAALVM_ADDITIONAL_ARGS} --jvm --vm.Xss2m --polyglot ${dir}/server.js 25 | -------------------------------------------------------------------------------- /fastr_node/server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | 6 | fs = require('fs'); 7 | 8 | // Load the R module 9 | var modelScript = fs.readFileSync(__dirname + "/model.r", "utf8"); 10 | Polyglot.eval("application/x-r", modelScript); 11 | 12 | // Import the function exported from the R module 13 | plotKMeans = Polyglot.import('plotkmeans'); 14 | plotCars = Polyglot.import('plotcars'); 15 | plotWeight = Polyglot.import('plotheightweight'); 16 | predictWeight = Polyglot.import('predictweight'); 17 | 18 | // Expressjs application: 19 | var express = require('express'); 20 | var app = express(); 21 | 22 | app.get('/kmeans', function (req, res) { 23 | console.log('generating kmeans graph'); 24 | res.send(plotKMeans(req.query.xaxis, req.query.yaxis, req.query.clusters)); 25 | }); 26 | 27 | app.get('/cars', function (req, res) { 28 | console.log('generating cars graph'); 29 | res.send(plotCars(req.query.xaxis, req.query.yaxis, req.query.zaxis)); 30 | }); 31 | 32 | app.get('/lm', function (req, res) { 33 | console.log('generating height/weight plot'); 34 | res.send(plotWeight()); 35 | }); 36 | 37 | app.get('/lm/predict', function (req, res) { 38 | console.log('predicting weight'); 39 | res.send('' + predictWeight(parseInt(req.query.height, 10))); 40 | }); 41 | 42 | app.use(express.static(__dirname + "/public")); 43 | var port = 12837; 44 | var server = app.listen(port, function() { 45 | console.log("Server listening on http://localhost:" + port); 46 | }); 47 | 48 | app.get('/exit', function(req, res) { 49 | res.status(200).send(''); 50 | server.close(); 51 | }); 52 | -------------------------------------------------------------------------------- /fastr_node/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | set -o xtrace 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | exec 3< <(${GRAALVM_DIR}/bin/node ${GRAALVM_ADDITIONAL_ARGS} --jvm --polyglot ${dir}/server.js) 24 | 25 | while read line; do 26 | if grep -q 'Server listening' <<< $line; then 27 | break 28 | fi 29 | done <&3 30 | 31 | port=12837 32 | 33 | function stop() { 34 | curl -s --noproxy localhost --request GET http://localhost:${port}/exit >/dev/null 35 | } 36 | 37 | # $1 message 38 | # $2 path to GET 39 | # $3 validation string 40 | function test() { 41 | echo "$1" 42 | if ! curl -s --include --noproxy localhost --request GET http://localhost:${port}/$2 | grep "$3" >/dev/null; then 43 | echo "ERROR" 44 | stop 45 | exit 1 46 | fi 47 | } 48 | 49 | echo -e "Testing GraalVM FastR Node.js interop example running at http://localhost:${port}\n" 50 | 51 | test "getting index.html" "index.html" "200 OK" 52 | test "getting kmeans visualization" "kmeans?xaxis=Sepal.Length&yaxis=Sepal.Width&clusters=4" " 3 || alive < 2) { 17 | result[[i,j]] <- FALSE 18 | } else if (alive == 2) { 19 | result[[i,j]] <- TRUE 20 | } else { 21 | result[[i,j]] <- m[[i,j]] 22 | } 23 | } 24 | } 25 | result 26 | } 27 | 28 | aliveNeighbors <- function(m, i, j) { 29 | cnt <- 0 30 | if (i > 1) cnt <- cnt + m[[i-1,j]] 31 | if (j > 1) cnt <- cnt + m[[i,j-1]] 32 | if (i < nrow(m)) cnt <- cnt + m[[i+1,j]] 33 | if (j < ncol(m)) cnt <- cnt + m[[i,j+1]] 34 | cnt 35 | } 36 | 37 | printMatrix <- function(m) { 38 | for (i in 1:nrow(m)) { 39 | for (j in 1:ncol(m)) 40 | cat(if (m[[i,j]]) '[]' else ' ') 41 | cat("\n") 42 | } 43 | } 44 | 45 | size <- 50 46 | m <- matrix(F, size, size) 47 | 48 | set.seed(123) 49 | 50 | for (i in 1:(size * size / 5)) { 51 | m[[runif(1)*nrow(m)+1,runif(1)*ncol(m)+1]] <- TRUE 52 | } 53 | 54 | for (i in 1:10) { 55 | printMatrix(m) 56 | cat("calculating 1000 iterations of a", size, "x", size," game of life\n") 57 | print(system.time(for (i in 1:1000) m <- step(m))) 58 | } 59 | 60 | q(status = (sum(m) != 113)) 61 | -------------------------------------------------------------------------------- /fastr_scalar/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | 7 | # Resolve the location of this script 8 | source="${BASH_SOURCE[0]}" 9 | while [ -h "$source" ] ; do 10 | prev_source="$source" 11 | source="$(readlink "$source")"; 12 | if [[ "$source" != /* ]]; then 13 | # if the link was relative, it was relative to where it came from 14 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 15 | source="$dir/$source" 16 | fi 17 | done 18 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 19 | 20 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 21 | 22 | exec ${GRAALVM_DIR}/bin/Rscript ${dir}/gameoflife.R 23 | -------------------------------------------------------------------------------- /fastr_scalar/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graalvm/fastr-examples/be8a58faac569e5e94b062bd44f7b89331447f81/fastr_scalar/screen.png -------------------------------------------------------------------------------- /install_components.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | $GRAALVM_DIR/bin/gu install -A nodejs 5 | $GRAALVM_DIR/bin/gu install -A ruby 6 | $GRAALVM_DIR/bin/gu install -A R 7 | -------------------------------------------------------------------------------- /r_java_bench/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![Results](results.png) 3 | 4 | # rJava package and built-in Java interoperability in FastR 5 | 6 | This benchmark demonstrates the difference between the performance of rJava on GNU-R, rJava on FastR and builtin Java interoperability in FastR. 7 | 8 | Note FastR provides custom patched version of rJava where the C 9 | code that handles the communication with JVM is replaced by R code 10 | that uses the builtin Java interoperability to achieve the same. 11 | 12 | ## Setup 13 | 14 | Follow the instructions from the top level [README](../README.md) to install and setup GraalVM. 15 | Install the patched version of rJava using: 16 | 17 | ``` 18 | git clone https://github.com/oracle/fastr.git /tmp/fastr-repo 19 | $GRAALVM_DIR/bin/R CMD INSTALL /tmp/fastr-repo/com.oracle.truffle.r.pkgs/rJava 20 | ``` 21 | 22 | Note: the example invokes Java compiler using `system2` builtin. 23 | For this to work you need to export variable `JAVA_HOME` pointing to Java installation. 24 | This is done automatically on GraalVM, but not if run these examples on GNU-R. 25 | 26 | ## Run 27 | 28 | Execute either `r_java_bench.R` or `fastr_interop_bench.R` using `Rscript`, for example: 29 | 30 | ``` 31 | $GRAALVM_DIR/bin/Rscript --jvm r_java_bench.R 32 | ``` 33 | -------------------------------------------------------------------------------- /r_java_bench/fastr_interop_bench.R: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 2 | # This file is made available under version 3 of the GNU General Public License. 3 | 4 | # This is the same benchmark as r_java_bench.R but using the built-in interop features of FastR, 5 | # which is much faster than the rJava emulation 6 | 7 | if (!any(R.version$engine == "FastR")) { 8 | cat("This script runs only in FastR, not in GNU-R\n") 9 | exit(1) 10 | } 11 | 12 | # Compile the Java class that we will use in the benchmark 13 | # Note: you need to have $JAVA_HOME variable defined in the environment 14 | source("java.R") 15 | # add the benchmark class to classpath 16 | java.addToClasspath(getwd()) 17 | 18 | # the object that we are going to use for the benchmark, 19 | # syntactically this is the only difference from the rJava example 20 | testObject <- new("RJavaBench") 21 | 22 | benchmark <- function(obj) { 23 | result <- 0L 24 | for (j in 1:100) { 25 | obj2 <- obj$objectFunction(obj) 26 | obj$intField <- as.integer(obj2$doubleField) 27 | for (i in 1:250) { 28 | result <- obj$intFunction(i, obj$intField) 29 | } 30 | } 31 | result 32 | } 33 | 34 | result <- 0L 35 | timings <- numeric(5) 36 | for (i in 1:10) { 37 | cat("iteration ", i, "\n") 38 | time <- system.time(r <- benchmark(testObject)) 39 | print(time) 40 | 41 | # we do some artificial computation with the result so that 42 | # the compiler cannnot possibly ignore the call to benchmark() altogether 43 | result <- result + if (r > 0) 1 else -1; 44 | # save the timing 45 | timings[[i]] <- time[[3]] 46 | } 47 | 48 | cat("The computed number is ", result, "\n") 49 | cat("The times are: ") 50 | dput(round(timings, 3)) 51 | 52 | # cleanup 53 | unlink("RJavaBench.java") 54 | unlink("RJavaBench.class") 55 | -------------------------------------------------------------------------------- /r_java_bench/java.R: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 2 | # This file is made available under version 3 of the GNU General Public License. 3 | 4 | # Compiles the following Java source 5 | # Note: you need to have $JAVA_HOME variable defined in the environment 6 | 7 | javaSource <- " 8 | public class RJavaBench { 9 | 10 | public int intField; 11 | public double doubleField; 12 | 13 | public int intFunction(int a, int b) { 14 | return a - b; 15 | } 16 | 17 | public RJavaBench objectFunction(RJavaBench a) { 18 | RJavaBench result = new RJavaBench(); 19 | result.intField = (intField + a.intField + 1) / 2; 20 | result.doubleField = (doubleField + a.doubleField) / 2; 21 | return result; 22 | } 23 | } 24 | " 25 | 26 | cat("Compiling the Java source code....") 27 | writeLines(javaSource, "RJavaBench.java") 28 | system("$JAVA_HOME/bin/javac RJavaBench.java") 29 | cat("DONE\n") 30 | -------------------------------------------------------------------------------- /r_java_bench/r_java_bench.R: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 2 | # This file is made available under version 3 of the GNU General Public License. 3 | 4 | # Compile the Java class that we will use in the benchmark 5 | # Note: you need to have $JAVA_HOME variable defined in the environment 6 | source("java.R") 7 | 8 | # rJava initialization 9 | library(rJava) 10 | .jinit() 11 | .jaddClassPath(getwd()) 12 | 13 | # the object that we are going to use for the benchmark 14 | testObject <- .jnew("RJavaBench") 15 | 16 | benchmark <- function(obj) { 17 | result <- 0L 18 | for (j in 1:100) { 19 | obj2 <- obj$objectFunction(obj) 20 | obj$intField <- as.integer(obj2$doubleField) 21 | for (i in 1:250) { 22 | result <- obj$intFunction(i, obj$intField) 23 | } 24 | } 25 | result 26 | } 27 | 28 | result <- 0L 29 | timings <- numeric(5) 30 | for (i in 1:10) { 31 | cat("iteration ", i, "\n") 32 | time <- system.time(r <- benchmark(testObject)) 33 | print(time) 34 | 35 | # we do some artificial computation with the result so that 36 | # the compiler cannot possibly ignore the call to benchmark() altogether 37 | result <- result + if (r > 0) 1 else -1; 38 | # save the timing 39 | timings[[i]] <- time[[3]] 40 | } 41 | 42 | cat("The computed number is ", result, "\n") 43 | cat("The times are: ") 44 | dput(round(timings, 3)) 45 | 46 | # cleanup 47 | unlink("RJavaBench.java") 48 | unlink("RJavaBench.class") 49 | -------------------------------------------------------------------------------- /r_java_bench/results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graalvm/fastr-examples/be8a58faac569e5e94b062bd44f7b89331447f81/r_java_bench/results.png -------------------------------------------------------------------------------- /r_java_bench/test.R: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 2 | # This file is made available under version 3 of the GNU General Public License. 3 | 4 | # Tests the examples 5 | 6 | # Compile the Java class that we will use in the benchmark 7 | # Note: you need to have $JAVA_HOME variable defined in the environment 8 | source("java.R") 9 | 10 | # rJava 11 | library(rJava) 12 | .jinit() 13 | .jaddClassPath(getwd()) 14 | 15 | obj <- .jnew("RJavaBench") 16 | obj2 <- obj$objectFunction(obj) 17 | obj$intField <- as.integer(obj2$doubleField) 18 | for (i in 1:10) { 19 | result <- obj$intFunction(i, obj$intField) 20 | } 21 | 22 | stopifnot(result == 10) 23 | 24 | # Interop 25 | obj <- new("RJavaBench") 26 | obj2 <- obj$objectFunction(obj) 27 | obj$intField <- as.integer(obj2$doubleField) 28 | for (i in 1:10) { 29 | result <- obj$intFunction(i, obj$intField) 30 | } 31 | 32 | stopifnot(result == 10) 33 | 34 | # cleanup 35 | unlink("RJavaBench.java") 36 | unlink("RJavaBench.class") 37 | -------------------------------------------------------------------------------- /r_java_bench/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | set -o xtrace 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | cd ${dir} 24 | ${GRAALVM_DIR}/bin/Rscript --jvm test.R 25 | cd - 26 | -------------------------------------------------------------------------------- /r_java_embedding/README.md: -------------------------------------------------------------------------------- 1 | 2 | ```shell 3 | The whole data frame printed in R: 4 | id name language 5 | 1 1 Florian Python 6 | 2 2 Lukas R 7 | 3 3 Mila Java 8 | 4 4 Paley Coq 9 | 5 5 Stepan C# 10 | 6 6 Tomas Java 11 | 7 7 Zbynek Scala 12 | --------- 13 | 14 | Filter out users with ID>2: 15 | id name language 16 | 3 3 Mila Java 17 | 4 4 Paley Coq 18 | 5 5 Stepan C# 19 | 6 6 Tomas Java 20 | 7 7 Zbynek Scala 21 | --------- 22 | 23 | How many users like Java: 2 24 | ``` 25 | 26 | # Embedding R as a scripting language into JVM applications 27 | 28 | This demo shows how to embed FastR into Java application and how to share data between Java and R. 29 | The Java program only needs to implement few proxies to transform the data into the shape of a 30 | data frame and then the R code can work with the data like with any other data frame. 31 | There is no need to copy or marshal the data between the two runtimes. 32 | 33 | ## Setup 34 | 35 | Follow the instructions from the top level [README](../README.md) to install and setup GraalVM. 36 | Build the sources with `./build.sh`. 37 | 38 | ## Run 39 | 40 | The example can be executed using the `run.sh` script. 41 | 42 | ## FastR Java API 43 | 44 | TODO: -------------------------------------------------------------------------------- /r_java_embedding/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | echo "Compiling the Java sources" 24 | mkdir -p ${dir}/bin 25 | ${GRAALVM_DIR}/bin/javac -d ${dir}/bin ${dir}/src/main/java/com/oracle/truffle/r/fastrembedding/*.java 26 | -------------------------------------------------------------------------------- /r_java_embedding/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | rm -rf ${dir}/bin 22 | -------------------------------------------------------------------------------- /r_java_embedding/expected.out: -------------------------------------------------------------------------------- 1 | The whole data frame printed in R: 2 | id name language 3 | 1 1 Florian Python 4 | 2 2 Lukas R 5 | 3 3 Mila Java 6 | 4 4 Paley Coq 7 | 5 5 Stepan C# 8 | 6 6 Tomas Java 9 | 7 7 Zbynek Scala 10 | --------- 11 | 12 | Filter out users with ID>2: 13 | id name language 14 | 3 3 Mila Java 15 | 4 4 Paley Coq 16 | 5 5 Stepan C# 17 | 6 6 Tomas Java 18 | 7 7 Zbynek Scala 19 | --------- 20 | 21 | How many users like Java: 2 22 | -------------------------------------------------------------------------------- /r_java_embedding/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FastRJ", 3 | "version": "1.0.0", 4 | "description": "Embedding FastR into Java demo", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "GraalVM team", 10 | "license": "Universal Permissive License (UPL)", 11 | "dependencies": { 12 | "express": "^4.15.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /r_java_embedding/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | ${GRAALVM_DIR}/bin/java -cp ${dir}/bin com.oracle.truffle.r.fastrembedding.FastREmbeddingDemo 24 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrembedding/FastREmbeddingDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | package com.oracle.truffle.r.fastrembedding; 6 | 7 | import java.util.function.Function; 8 | 9 | import org.graalvm.polyglot.Context; 10 | import org.graalvm.polyglot.Value; 11 | import org.graalvm.polyglot.proxy.ProxyArray; 12 | 13 | public class FastREmbeddingDemo { 14 | 15 | public static final class User { 16 | public final int id; 17 | public final String name; 18 | public final String favoriteLanguage; 19 | 20 | public User(int id, String name, String favoriteLanguage) { 21 | this.id = id; 22 | this.name = name; 23 | this.favoriteLanguage = favoriteLanguage; 24 | } 25 | } 26 | 27 | public static class NameColumn implements ProxyArray { 28 | private final User[] users; 29 | 30 | public NameColumn(User[] users) { 31 | this.users = users; 32 | } 33 | 34 | public Object get(long index) { 35 | return users[(int) index].name; 36 | } 37 | 38 | public void set(long index, Value value) { 39 | throw new UnsupportedOperationException(); 40 | } 41 | 42 | public long getSize() { 43 | return users.length; 44 | } 45 | } 46 | 47 | public static class IdColumn implements ProxyArray { 48 | private final User[] users; 49 | 50 | public IdColumn(User[] users) { 51 | this.users = users; 52 | } 53 | 54 | public Object get(long index) { 55 | return (Object) users[(int) index].id; 56 | } 57 | 58 | public void set(long index, Value value) { 59 | throw new UnsupportedOperationException(); 60 | } 61 | 62 | public long getSize() { 63 | return users.length; 64 | } 65 | } 66 | 67 | public static class AnyColumn implements ProxyArray { 68 | private final User[] users; 69 | private final Function getter; 70 | 71 | public AnyColumn(User[] users, Function getter) { 72 | this.users = users; 73 | this.getter = getter; 74 | } 75 | 76 | 77 | @Override 78 | public Object get(long index) { 79 | return getter.apply(users[(int) index]); 80 | } 81 | 82 | @Override 83 | public void set(long index, Value value) { 84 | throw new UnsupportedOperationException(); 85 | } 86 | 87 | @Override 88 | public long getSize() { 89 | return users.length; 90 | } 91 | } 92 | 93 | public static class UsersTable { 94 | public final IdColumn id; 95 | public final NameColumn name; 96 | public final AnyColumn language; 97 | 98 | public UsersTable(User[] users) { 99 | this.id = new IdColumn(users); 100 | this.name = new NameColumn(users); 101 | this.language = new AnyColumn(users, x -> x.favoriteLanguage); 102 | } 103 | } 104 | 105 | public static void main(String[] args) { 106 | Context context = Context.newBuilder("R").allowAllAccess(true).build(); 107 | Value rFunction = context.eval("R", 108 | "function(table) { " + 109 | " table <- as.data.frame(table);" + 110 | " cat('The whole data frame printed in R:\n');" + 111 | " print(table);" + 112 | " cat('---------\n\n');" + 113 | 114 | " cat('Filter out users with ID>2:\n');" + 115 | " print(table[table$id > 2,]);" + 116 | " cat('---------\n\n');" + 117 | 118 | " cat('How many users like Java: ');" + 119 | " cat(nrow(table[table$language == 'Java',]), '\n');" + 120 | "}"); 121 | User[] data = getUsers(); 122 | rFunction.execute(new UsersTable(data)); 123 | } 124 | 125 | private static User[] getUsers() { 126 | return new User[] { 127 | new User(1, "Florian", "Python"), 128 | new User(2, "Lukas", "R"), 129 | new User(3, "Mila", "Java"), 130 | new User(4, "Paley", "Coq"), 131 | new User(5, "Stepan", "C#"), 132 | new User(6, "Tomas", "Java"), 133 | new User(7, "Zbynek", "Scala"), 134 | }; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/BrexitHandler.R: -------------------------------------------------------------------------------- 1 | require(jsonlite) 2 | require(dplyr) 3 | require(ggplot2) 4 | 5 | # Plots a simple bar chart of the brexit petition data and returns the SVG representation of the plot. 6 | svgExample1 <- function(model) { 7 | svg() 8 | print(ggplot(model, aes(name, signature_count, fill = signature_count)) + geom_col()) 9 | grDevices:::svg.off() 10 | } 11 | 12 | brexit <- fromJSON('https://petition.parliament.uk/petitions/241584.json') 13 | brexitByConstituency <- brexit$data$attributes$signatures_by_constituency %>% arrange(desc(signature_count)) 14 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/BrexitHandler.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | 6 | import org.graalvm.polyglot.Value; 7 | 8 | public final class BrexitHandler { 9 | 10 | private final Value plotFn; 11 | private final Value plotData; 12 | private final Value plotHeadDataFn; 13 | 14 | public BrexitHandler(FastR fastR) { 15 | this.plotHeadDataFn = fastR.asFunction("head(_data_, _n_)"); 16 | 17 | RBundle bundle = new RBundle(fastR, BrexitHandler.class); 18 | this.plotFn = bundle.get("svgExample1"); 19 | this.plotData = bundle.get("brexitByConstituency"); 20 | } 21 | 22 | public static BrexitHandler getHandler(Map request) { 23 | return FastR.getInstance().getOrCreate(BrexitHandler.class, fastR -> new BrexitHandler(fastR)); 24 | } 25 | 26 | public String plotChart(int maxCols) throws IOException { 27 | Value out = plotFn.execute(plotHeadDataFn.execute(plotData, maxCols)); 28 | return out.asString(); 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/Dplyr.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import java.util.function.Function; 4 | 5 | public final class Dplyr { 6 | 7 | private final FastR fastR; 8 | 9 | public Dplyr(FastR fastR) { 10 | this.fastR = fastR; 11 | this.fastR.require("dplyr"); 12 | } 13 | 14 | public FastR getFastR() { 15 | return fastR; 16 | } 17 | 18 | public DplyrQueryBuilder newQueryBuilder() { 19 | return new DplyrQueryBuilder(this); 20 | } 21 | 22 | public DplyrQueryBuilder newQueryBuilder(String head) { 23 | return new DplyrQueryBuilder(this, head); 24 | } 25 | 26 | public Dplyr stringsAsFactors(boolean flag) { 27 | fastR.setOption("stringsAsFactors", flag); 28 | return this; 29 | } 30 | 31 | @FunctionalInterface 32 | public interface F2 { 33 | R apply(T1 t1, T2 t2); 34 | } 35 | 36 | @FunctionalInterface 37 | public interface F3 { 38 | R apply(T1 t1, T2 t2, T3 t3); 39 | } 40 | 41 | @FunctionalInterface 42 | public interface F4 { 43 | R apply(T1 t1, T2 t2, T3 t3, T4 t4); 44 | } 45 | 46 | public Function resultAsVector(Function fn) { 47 | return (t) -> { 48 | return fastR.asVector(fn.apply(t)); 49 | }; 50 | } 51 | 52 | public F2 resultAsVector(F2 fn) { 53 | return (t1, t2) -> { 54 | return fastR.asVector(fn.apply(t1, t2)); 55 | }; 56 | } 57 | 58 | public F3 resultAsVector(F3 fn) { 59 | return (t1, t2, t3) -> { 60 | return fastR.asVector(fn.apply(t1, t2, t3)); 61 | }; 62 | } 63 | 64 | public F4 resultAsVector(F4 fn) { 65 | return (t1, t2, t3, t4) -> { 66 | return fastR.asVector(fn.apply(t1, t2, t3, t4)); 67 | }; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/DplyrQueryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.function.Function; 8 | 9 | import org.graalvm.polyglot.Value; 10 | 11 | import com.oracle.truffle.r.fastrj.Dplyr.F2; 12 | import com.oracle.truffle.r.fastrj.Dplyr.F3; 13 | import com.oracle.truffle.r.fastrj.Dplyr.F4; 14 | 15 | public final class DplyrQueryBuilder { 16 | 17 | private final Dplyr dplyr; 18 | private final String head; 19 | private final List steps = new ArrayList(); 20 | private final Map queryEnvEntries = new HashMap(); 21 | 22 | DplyrQueryBuilder(Dplyr dplyr) { 23 | this(dplyr, null); 24 | } 25 | 26 | DplyrQueryBuilder(Dplyr dplyr, String head) { 27 | this.dplyr = dplyr; 28 | this.head = head; 29 | } 30 | 31 | public DplyrQueryBuilder putEnvironmentEntries(Map queryEnvEntries) { 32 | this.queryEnvEntries.putAll(queryEnvEntries); 33 | return this; 34 | } 35 | 36 | private void buildStep(String stepName, String... args) { 37 | steps.add(new StringBuilder().append(stepName).append("(").append(String.join(",", args)).append(")").toString()); 38 | } 39 | 40 | public DplyrQueryBuilder select(String... columns) { 41 | buildStep("select", columns); 42 | return this; 43 | } 44 | 45 | public DplyrQueryBuilder filter(String... predicates) { 46 | buildStep("filter", predicates); 47 | return this; 48 | } 49 | 50 | public DplyrQueryBuilder arrange(String... columns) { 51 | buildStep("arrange", columns); 52 | return this; 53 | } 54 | 55 | public DplyrQueryBuilder group_by(String... columns) { 56 | buildStep("group_by", columns); 57 | return this; 58 | } 59 | 60 | public DplyrQueryBuilder summarise(String... columns) { 61 | buildStep("summarise", columns); 62 | return this; 63 | } 64 | 65 | public DplyrQueryBuilder do_(String... computations) { 66 | buildStep("do", computations); 67 | return this; 68 | } 69 | 70 | public DplyrQueryBuilder mutate(String... columnMutations) { 71 | buildStep("mutate", columnMutations); 72 | return this; 73 | } 74 | 75 | public DplyrQueryBuilder mutate_if(String condition, String columnMutation) { 76 | buildStep("mutate_if", condition, columnMutation); 77 | return this; 78 | } 79 | 80 | public DplyrQueryBuilder assignFilter(String name, Function pred) { 81 | queryEnvEntries.put(name, dplyr.resultAsVector(new Function, Object>() { 82 | 83 | @Override 84 | public List apply(List t) { 85 | // Each element indicates whether the row is retained 86 | List retained = new ArrayList<>(); 87 | for (int i = 0; i < t.size(); i++) { 88 | boolean retainIt = pred.apply(t.get(i)); 89 | retained.add(retainIt); 90 | } 91 | return retained; 92 | } 93 | 94 | })); 95 | return this; 96 | } 97 | 98 | public DplyrQueryBuilder assignFilter(String name, F2 pred) { 99 | queryEnvEntries.put(name, dplyr.resultAsVector(new F2, List, Object>() { 100 | 101 | @Override 102 | public List apply(List t1, List t2) { 103 | // Each element indicates whether the row is retained 104 | List retained = new ArrayList<>(); 105 | for (int i = 0; i < t1.size(); i++) { 106 | boolean retainIt = pred.apply(t1.get(i), t2.get(i)); 107 | retained.add(retainIt); 108 | } 109 | return retained; 110 | } 111 | 112 | })); 113 | return this; 114 | } 115 | 116 | public DplyrQueryBuilder assignFilter(String name, F3 pred) { 117 | queryEnvEntries.put(name, dplyr.resultAsVector(new F3, List, List, Object>() { 118 | 119 | @Override 120 | public List apply(List t1, List t2, List t3) { 121 | // Each element indicates whether the row is retained 122 | List retained = new ArrayList<>(); 123 | for (int i = 0; i < t1.size(); i++) { 124 | boolean retainIt = pred.apply(t1.get(i), t2.get(i), t3.get(i)); 125 | retained.add(i, retainIt); 126 | } 127 | return retained; 128 | } 129 | 130 | })); 131 | return this; 132 | } 133 | 134 | public DplyrQueryBuilder assignFilter(String name, F4 pred) { 135 | queryEnvEntries.put(name, dplyr.resultAsVector(new F4, List, List, List, Object>() { 136 | 137 | @Override 138 | public List apply(List t1, List t2, List t3, List t4) { 139 | // Each element indicates whether the row is retained 140 | List retained = new ArrayList<>(); 141 | for (int i = 0; i < t1.size(); i++) { 142 | boolean retainIt = pred.apply(t1.get(i), t2.get(i), t3.get(i), t4.get(i)); 143 | retained.add(i, retainIt); 144 | } 145 | return retained; 146 | } 147 | 148 | })); 149 | return this; 150 | } 151 | 152 | public DplyrQueryBuilder assignAggregator(String name, Object aggr) { 153 | assign(name, aggr); 154 | return this; 155 | } 156 | 157 | public DplyrQueryBuilder assign(String name, Object value) { 158 | queryEnvEntries.put(name, value); 159 | return this; 160 | } 161 | 162 | private String getQuerySource() { 163 | return (head == null ? "_table_" : head)+ " %>% " + String.join(" %>% ", steps); 164 | } 165 | 166 | public Value build() { 167 | return dplyr.getFastR().asFunction(getQuerySource(), queryEnvEntries); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/FastR.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | import java.util.AbstractList; 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.HashMap; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Set; 13 | import java.util.function.BiFunction; 14 | import java.util.function.Function; 15 | import java.util.function.Supplier; 16 | 17 | import org.graalvm.polyglot.Context; 18 | import org.graalvm.polyglot.Value; 19 | 20 | public final class FastR implements Closeable { 21 | 22 | private static final String SET_OPTION = "function(name, value) { " + 23 | "args <- list(); " + 24 | "args[name] <- value; " + 25 | "options(args)" + 26 | "}"; 27 | 28 | private static final String AS_VECTOR = "function(x) sapply(x, identity)"; 29 | 30 | private static final String SET_NAMES = "function(x, nm) { names(x) <- as.character(nm); x }"; 31 | 32 | private static final String PARSE = "function(src) parse(text = src)"; 33 | 34 | private static final String AS_FUNCTION = "function(fml, bd, envir) {\n" + 35 | " nm <- as.character(fml)\n" + 36 | " fml <- vector('list', length(nm))\n" + 37 | " names(fml) <- nm\n" + 38 | " fml[[length(fml) + 1]] <- bd\n" + 39 | " as.function(fml, envir = envir)\n" + 40 | "}\n"; 41 | 42 | final Context plgCtx; 43 | private final Value setOption; 44 | private final Value asVector; 45 | private final Value parse; 46 | private final Value asFunction; 47 | private final Value setNames; 48 | 49 | private final Map functions = new HashMap(); 50 | 51 | public FastR() { 52 | this(Context.newBuilder("R").allowAllAccess(true).build()); 53 | } 54 | 55 | private FastR(Context plgCtx) { 56 | this.plgCtx = plgCtx; 57 | this.setOption = eval(SET_OPTION); 58 | this.asVector = eval(AS_VECTOR); 59 | this.parse = eval(PARSE); 60 | this.asFunction = eval(AS_FUNCTION); 61 | this.setNames = eval(SET_NAMES); 62 | } 63 | 64 | public static FastR getInstance() { 65 | return getInstance(Context.getCurrent()); 66 | } 67 | 68 | public static FastR getInstance(Context plgCtx) { 69 | Value fastrVal = plgCtx.eval("R", "mget('__FastR__', envir= .GlobalEnv, ifnotfound=list('__FastR__' = NULL))").getMember("__FastR__"); 70 | FastR fastR = fastrVal.isNull() ? null : (FastR) fastrVal.asHostObject(); 71 | if (fastR == null) { 72 | fastR = new FastR(plgCtx); 73 | fastR.assign("__FastR__", fastR, fastR.globalEnvironment()); 74 | } 75 | return fastR; 76 | } 77 | 78 | public T getOrCreate(Class valCls, Function supplier) { 79 | return getOrCreate(valCls.getName(), supplier); 80 | } 81 | 82 | public T getOrCreate(String name, Function supplier) { 83 | Value tVal = call("mget", name, named("envir", globalEnvironment()), named("ifnotfound", list(named(name, null)))).getMember(name); 84 | @SuppressWarnings("unchecked") 85 | T t = tVal.isNull() ? null : (T) tVal.asHostObject(); 86 | if (t == null) { 87 | t = supplier.apply(this); 88 | assign(name, t, globalEnvironment()); 89 | } 90 | return t; 91 | } 92 | 93 | public Value library(String packageName) { 94 | return execute("library", packageName); 95 | } 96 | 97 | public boolean require(String packageName) { 98 | return call("require", packageName, named("character.only", true)).asBoolean(); 99 | } 100 | 101 | public void installPackage(String packageName) { 102 | execute("install.packages", packageName); 103 | } 104 | 105 | public Value environment() { 106 | return execute("environment"); 107 | } 108 | 109 | public Value newEnvironment() { 110 | return execute("new.env"); 111 | } 112 | 113 | public Value newEnvironment(Map entries) { 114 | Value env = newEnvironment(); 115 | for (Map.Entry entry : entries.entrySet()) { 116 | assign(entry.getKey(), entry.getValue(), env); 117 | } 118 | return env; 119 | } 120 | 121 | 122 | public Value globalEnvironment() { 123 | return eval(".GlobalEnv"); 124 | } 125 | 126 | public Value execute(String function, Object... args) { 127 | Value fn = functions.get(function); 128 | if (fn == null) { 129 | fn = eval(function); 130 | functions.put(function, fn); 131 | } 132 | 133 | return fn.execute(args); 134 | } 135 | 136 | public Value call(String function, Object... args) { 137 | Value fn = functions.get(function); 138 | if (fn == null) { 139 | fn = eval(function); 140 | functions.put(function, fn); 141 | } 142 | 143 | List actualArgs = new ArrayList(); 144 | List argNames = new ArrayList(); 145 | for (int i = 0; i < args.length; i++) { 146 | if (args[i] instanceof NamedArg) { 147 | actualArgs.add(((NamedArg)args[i]).value); 148 | argNames.add(((NamedArg)args[i]).name); 149 | } else { 150 | actualArgs.add(args[i]); 151 | argNames.add(""); 152 | } 153 | } 154 | 155 | Value argList = execute("as.list", actualArgs); 156 | argList = setNames.execute(argList, argNames); 157 | 158 | return execute("do.call", function, argList); 159 | } 160 | 161 | public static NamedArg named(String name, Object value) { 162 | return new NamedArg(name, value); 163 | } 164 | 165 | public Context getContext() { 166 | return this.plgCtx; 167 | } 168 | 169 | public Value eval(CharSequence source) { 170 | return this.plgCtx.eval("R", source); 171 | } 172 | 173 | public Value parse(CharSequence source) { 174 | return parse.execute(source); 175 | } 176 | 177 | public static R treewalk(Value tree, R input, BiFunction visitor) { 178 | R result = visitor.apply(input, tree); 179 | if (tree.hasArrayElements()) { 180 | long childrenSize = tree.getArraySize(); 181 | for (int i = 0; i < childrenSize; i++) { 182 | Value child = tree.getArrayElement(i); 183 | result = treewalk(child, result, visitor); 184 | } 185 | } 186 | return result; 187 | } 188 | 189 | public Value get(String name) { 190 | return execute("get", name); 191 | } 192 | 193 | public Value getOrElse(String name, Object ifnotfound) { 194 | return execute("mget", name, named("ifnotfound", list(named(name, ifnotfound)))).getMember(name); 195 | } 196 | 197 | public Value get(String name, Value envir) { 198 | return call("get", name, named("envir", envir)); 199 | } 200 | 201 | public Value getOrElse(String name, Value envir, Object ifnotfound) { 202 | return call("mget", name, named("envir", envir), named("ifnotfound", list(named(name, ifnotfound)))).getMember(name); 203 | } 204 | 205 | public FastR assign(String name, Object value) { 206 | assign(name, value, environment()); 207 | return this; 208 | } 209 | 210 | public FastR assign(String name, Object value, Value envir) { 211 | call("assign", name, value, named("envir", envir)); 212 | return this; 213 | } 214 | 215 | public FastR setOption(String name, Object value) { 216 | setOption.execute(name, value); 217 | return this; 218 | } 219 | 220 | public Value getOption(String name) { 221 | return execute("getOption", name); 222 | } 223 | 224 | public Value asVector(Object x) { 225 | return asVector.execute(x); 226 | } 227 | 228 | public Value list(Object... elements) { 229 | return call("list", elements); 230 | } 231 | 232 | public Value asDataFrame(Object x) { 233 | return execute("as.data.frame", x); 234 | } 235 | 236 | public String asString(Object x) { 237 | return execute("as.character", x).asString(); 238 | } 239 | 240 | public Value asFunction(CharSequence expression) { 241 | return asFunction(expression, Collections.emptyMap()); 242 | } 243 | 244 | public Value asFunction(CharSequence expression, Map environment) { 245 | Value bodyAST = parse(expression); 246 | return asFunction(bodyAST.getArrayElement(0), environment); 247 | } 248 | 249 | public Value asFunction(Value bodyAST) { 250 | return asFunction(bodyAST, Collections.emptyMap()); 251 | } 252 | 253 | public Value asFunction(Value bodyAST, Map environment) { 254 | Value enclosingEnv = newEnvironment(environment); 255 | List formals = retrieveFormals(bodyAST); 256 | return asFunction(formals, bodyAST, enclosingEnv); 257 | } 258 | 259 | public Value asFunction(List formals, Value bodyAST, Value enclosingEnv) { 260 | return asFunction.execute(formals, bodyAST, enclosingEnv); 261 | } 262 | 263 | public int nrow(Value table) { 264 | return execute("nrow", table).asInt(); 265 | } 266 | 267 | public int ncol(Value table) { 268 | return execute("ncol", table).asInt(); 269 | } 270 | 271 | public Value readCSV(String filePath) { 272 | return execute("read.csv", filePath); 273 | } 274 | 275 | public static List> asRows(final Value dataFrame) { 276 | if (!dataFrame.hasArrayElements()) { 277 | return Collections.singletonList(Collections.singletonList(dataFrame)); 278 | } 279 | 280 | final int ncol = (int) dataFrame.getArraySize(); 281 | if (ncol == 0) { 282 | return Collections.emptyList(); 283 | } 284 | 285 | final int nrow = (int) dataFrame.getArrayElement(0).getArraySize(); 286 | if (nrow == 0) { 287 | return Collections.emptyList(); 288 | } 289 | 290 | return new AbstractList>() { 291 | 292 | @Override 293 | public List get(int index) { 294 | return new AbstractList() { 295 | 296 | @Override 297 | public Value get(int colIndex) { 298 | return dataFrame.getArrayElement(colIndex).getArrayElement(index); 299 | } 300 | 301 | @Override 302 | public int size() { 303 | return ncol; 304 | } 305 | }; 306 | } 307 | 308 | @Override 309 | public int size() { 310 | return nrow; 311 | } 312 | 313 | }; 314 | } 315 | 316 | public boolean isSymbol(Value x) { 317 | return execute("is.symbol", x).asBoolean(); 318 | } 319 | 320 | @FunctionalInterface 321 | public interface VarArgFunction { 322 | T execute(Object... args); 323 | } 324 | 325 | private List retrieveFormals(Value queryAST) { 326 | Set seenFormals = new HashSet(); 327 | List queryFormals = new ArrayList(); 328 | FastR.treewalk(queryAST, null, (res, node) -> { 329 | if (isSymbol(node)) { 330 | String sym = asString(node); 331 | if (sym.startsWith("_") && sym.endsWith("_")) { 332 | if (!seenFormals.contains(sym)) { 333 | seenFormals.add(sym); 334 | queryFormals.add(sym); 335 | } 336 | } 337 | } 338 | return res; 339 | }); 340 | return queryFormals; 341 | } 342 | 343 | public final static class NamedArg { 344 | private final String name; 345 | private final Object value; 346 | 347 | public NamedArg(String name, Object value) { 348 | this.name = name; 349 | this.value = value; 350 | } 351 | 352 | } 353 | 354 | @Override 355 | public void close() throws IOException { 356 | plgCtx.close(); 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/FastREmbeddingDemo.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import static com.oracle.truffle.r.fastrj.FastR.asRows; 4 | import static com.oracle.truffle.r.fastrj.FastR.named; 5 | 6 | import java.awt.BorderLayout; 7 | import java.awt.Container; 8 | import java.awt.Dimension; 9 | import java.awt.FlowLayout; 10 | import java.awt.event.ActionListener; 11 | import java.awt.image.BufferedImage; 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.util.List; 15 | import java.util.concurrent.Callable; 16 | import java.util.concurrent.atomic.AtomicInteger; 17 | import java.util.function.Function; 18 | 19 | import javax.imageio.ImageIO; 20 | import javax.swing.JComboBox; 21 | import javax.swing.JFrame; 22 | import javax.swing.JLabel; 23 | import javax.swing.JPanel; 24 | import javax.swing.WindowConstants; 25 | import javax.swing.border.EmptyBorder; 26 | 27 | import org.graalvm.polyglot.Context; 28 | import org.graalvm.polyglot.Value; 29 | import org.graalvm.polyglot.proxy.ProxyArray; 30 | 31 | public class FastREmbeddingDemo { 32 | 33 | public static final class User { 34 | public final int id; 35 | public final String name; 36 | public final String favoriteLanguage; 37 | 38 | public User(int id, String name, String favoriteLanguage) { 39 | this.id = id; 40 | this.name = name; 41 | this.favoriteLanguage = favoriteLanguage; 42 | } 43 | 44 | public String toDisplayName(String prefix) { 45 | return prefix + name; 46 | } 47 | } 48 | 49 | public static class NameColumn implements ProxyArray { 50 | private final User[] users; 51 | 52 | public NameColumn(User[] users) { 53 | this.users = users; 54 | } 55 | 56 | public Object get(long index) { 57 | return users[(int) index].name; 58 | } 59 | 60 | public void set(long index, Value value) { 61 | throw new UnsupportedOperationException(); 62 | } 63 | 64 | public long getSize() { 65 | return users.length; 66 | } 67 | } 68 | 69 | public static class IdColumn implements ProxyArray { 70 | private final User[] users; 71 | 72 | public IdColumn(User[] users) { 73 | this.users = users; 74 | } 75 | 76 | public Object get(long index) { 77 | return (Object) users[(int) index].id; 78 | } 79 | 80 | public void set(long index, Value value) { 81 | throw new UnsupportedOperationException(); 82 | } 83 | 84 | public long getSize() { 85 | return users.length; 86 | } 87 | } 88 | 89 | public static class AnyColumn implements ProxyArray { 90 | private final User[] users; 91 | private final Function getter; 92 | 93 | public AnyColumn(User[] users, Function getter) { 94 | this.users = users; 95 | this.getter = getter; 96 | } 97 | 98 | 99 | @Override 100 | public Object get(long index) { 101 | return getter.apply(users[(int) index]); 102 | } 103 | 104 | @Override 105 | public void set(long index, Value value) { 106 | throw new UnsupportedOperationException(); 107 | } 108 | 109 | @Override 110 | public long getSize() { 111 | return users.length; 112 | } 113 | } 114 | 115 | public static class UsersTable { 116 | public final IdColumn id; 117 | public final NameColumn name; 118 | public final AnyColumn language; 119 | 120 | public UsersTable(User[] users) { 121 | this.id = new IdColumn(users); 122 | this.name = new NameColumn(users); 123 | this.language = new AnyColumn(users, x -> x.favoriteLanguage); 124 | } 125 | } 126 | 127 | static Function, Object> myAggr = x -> { 128 | return x.stream().reduce((res, b) -> res + b).get(); 129 | }; 130 | 131 | static Function myAggr2 = x -> { 132 | // TODO: x can be NULL, NA, a scalar or a list 133 | return 1; 134 | }; 135 | 136 | //static final FastR fastR = new FastR(); 137 | //static final Dplyr dplyr = new Dplyr(fastR); 138 | static { 139 | //dplyr.stringsAsFactors(false); 140 | } 141 | 142 | public static void main(String[] args) throws IOException { 143 | 144 | FastR fastR = new FastR(); 145 | 146 | // polyglotUsage(); 147 | 148 | // IrisHandler h = new IrisHandler(fastR); 149 | // Object res = h.generateTable(1); 150 | // 151 | // basicFastR(); 152 | // 153 | // 154 | // usingPackages(); 155 | 156 | // usingJavaObjects(); 157 | // 158 | // parseSimpleQuery(fastR); 159 | // 160 | // parseSimpleParamQuery(fastR); 161 | // 162 | // parseSimpleParamQueryFromBundle(fastR); 163 | // 164 | // buildSimpleQuery(fastR); 165 | 166 | // 167 | // buildQueryOverJavaObject(); 168 | // 169 | buildQueryWithCustomFilter(fastR); 170 | // 171 | // buildQueryWithCustomAggregator(); 172 | // 173 | // loadAndQueryCSVFile(); 174 | // 175 | // queryParameters(); 176 | // 177 | // javax.swing.SwingUtilities.invokeLater(() -> plotInJava1()); 178 | // 179 | // javax.swing.SwingUtilities.invokeLater(() -> plotInJava2()); 180 | // 181 | // javaHeadlessGraphics(); 182 | } 183 | 184 | private static void plotInJava1() { 185 | FastR fastR = new FastR(); 186 | fastR.require("ggplot2"); 187 | 188 | Value iris = fastR.eval("iris"); 189 | PlotJPanel plotPanel = PlotJPanel.createSimplePlotPanel(fastR, 190 | "ggplot(_iris_, aes(x = Petal.Width, y = Sepal.Length)) + \n" + 191 | " geom_point() +\n" + 192 | " stat_smooth(method = \"lm\", col = \"red\")", 193 | () -> iris); 194 | plotPanel.showFrame("Iris Regression", 700, 500); 195 | } 196 | 197 | 198 | private static void plotInJava2() { 199 | FastR fastR = new FastR(); 200 | fastR.library("dplyr"); 201 | fastR.library("ggplot2"); 202 | 203 | Value sepalPredQ = fastR.asFunction("iris %>% group_by(Species) %>% do(pred = lm(Sepal.Width ~ Petal.Width, .))"); 204 | Value sepalPred = sepalPredQ.execute(); 205 | 206 | JFrame frame = new JFrame("Iris Regression"); 207 | frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 208 | frame.setPreferredSize(new Dimension(750, 500)); 209 | 210 | Value[] speciesModel = GraalVM.asArray(sepalPred.getMember("Species")); 211 | 212 | JComboBox speciesCombo = new JComboBox<>(speciesModel); 213 | speciesCombo.setSelectedIndex(0); 214 | 215 | PlotJPanel plotPanel = PlotJPanel.createRegressionPlotPanel(fastR.getContext(), () -> { 216 | Value selectedItem = speciesCombo.getItemAt(speciesCombo.getSelectedIndex()); 217 | return sepalPred.getMember("pred").getArrayElement(selectedItem.asInt() - 1); 218 | }); 219 | 220 | ActionListener updatePlot = e -> plotPanel.repaint(); 221 | speciesCombo.addActionListener(updatePlot); 222 | 223 | JPanel options = new JPanel(); 224 | options.setLayout(new FlowLayout(FlowLayout.CENTER)); 225 | options.add(new JLabel("Species: ")); 226 | options.add(speciesCombo); 227 | speciesCombo.setBorder(new EmptyBorder(0, 0, 0, 40)); 228 | 229 | frame.setLayout(new BorderLayout(20, 20)); 230 | Container pane = frame.getContentPane(); 231 | pane.add(options, BorderLayout.PAGE_START); 232 | pane.add(plotPanel, BorderLayout.CENTER); 233 | 234 | frame.pack(); 235 | frame.setVisible(true); 236 | } 237 | 238 | static void javaHeadlessGraphics() { 239 | FastR fastR = new FastR(); 240 | fastR.library("dplyr"); 241 | fastR.library("ggplot2"); 242 | 243 | Value sepalPredQ = fastR.asFunction("iris %>% group_by(Species) %>% do(pred = lm(Sepal.Width ~ Petal.Width, .))"); 244 | Value sepalPred = sepalPredQ.execute(); 245 | AtomicInteger currentModelIndex = new AtomicInteger(); 246 | PlotJPanel plotPanel = PlotJPanel.createRegressionPlotPanel(fastR.getContext(), () -> { 247 | return sepalPred.getMember("pred").getArrayElement(currentModelIndex.get()); 248 | }); 249 | plotPanel.setSize(700, 500); 250 | 251 | int nrow = fastR.nrow(sepalPred); 252 | for (int i = 0; i < nrow; i++) { 253 | currentModelIndex.set(i); 254 | BufferedImage image = plotPanel.paintHeadless(); 255 | 256 | // Save the image to file 257 | String dest = "test-" + i + ".png"; 258 | try { 259 | ImageIO.write(image, "png", new File(dest)); 260 | } catch (IOException e) { 261 | e.printStackTrace(); 262 | } 263 | } 264 | 265 | } 266 | 267 | private static void queryParameters(FastR fastR) { 268 | Value msleepDF = fastR.readCSV("src/main/resources/msleep_ggplot2.csv"); 269 | String msleepQ2 = "_msleep_ %>%" + 270 | " group_by(order) %>%" + 271 | " summarise(avg_sleep = _weight1_ * mean(sleep_total)," + 272 | " min_sleep = _weight2_ * min(sleep_total)," + 273 | " max_sleep = _weight3_ * max(sleep_total)," + 274 | " total = n())"; 275 | 276 | Value dplyrQuery2 = fastR.asFunction(msleepQ2); 277 | Value res = dplyrQuery2.execute(msleepDF, 1, 2, 3); 278 | 279 | for (List row : asRows(res)) { 280 | System.out.println(row); 281 | } 282 | } 283 | 284 | private static void loadAndQueryCSVFile(FastR fastR) { 285 | Value msleepDF = fastR.readCSV("src/main/resources/msleep_ggplot2.csv"); 286 | fastR.assign("msleep", msleepDF); 287 | 288 | String msleepQ1 = "msleep %>%" + 289 | " group_by(order) %>%" + 290 | " summarise(avg_sleep = mean(sleep_total)," + 291 | " min_sleep = min(sleep_total)," + 292 | " max_sleep = max(sleep_total)," + 293 | " total = n())"; 294 | 295 | Value dplyrQuery1 = fastR.asFunction(msleepQ1); 296 | Value res = dplyrQuery1.execute(); 297 | 298 | for (List row : asRows(res)) { 299 | System.out.println(row); 300 | } 301 | } 302 | 303 | private static void buildQueryOverJavaObject(FastR fastR) { 304 | Dplyr dplyr = new Dplyr(fastR); 305 | DplyrQueryBuilder dplyrBuilder = dplyr.newQueryBuilder(); 306 | dplyrBuilder.select("id", "name", "language"). 307 | group_by("language"). 308 | summarise("count = n()"); 309 | 310 | Value dplyrQuery0 = dplyrBuilder.build(); 311 | 312 | User[] data = getUsers(); 313 | Value df = fastR.asDataFrame(new UsersTable(data)); 314 | Value res = dplyrQuery0.execute(df); 315 | 316 | for (List row : asRows(res)) { 317 | System.out.println(row); 318 | } 319 | } 320 | 321 | private static boolean isAllowedMPG(double mpg) { 322 | return mpg > 17; 323 | } 324 | 325 | private static void buildQueryWithCustomFilter(FastR fastR) { 326 | 327 | Dplyr dplyr = new Dplyr(fastR); 328 | dplyr.stringsAsFactors(false); 329 | 330 | DplyrQueryBuilder allowedMPGBuilder = dplyr.newQueryBuilder("mtcars"); 331 | allowedMPGBuilder. 332 | assignFilter("myFilter", (mpg) -> isAllowedMPG(mpg + 2.2)); 333 | 334 | allowedMPGBuilder.filter("myFilter(mpg)").summarise("total = n()"); 335 | 336 | Value dplyrQuery0 = allowedMPGBuilder.build(); 337 | Value res = dplyrQuery0.execute(); 338 | 339 | System.out.println(res); 340 | } 341 | 342 | private static void buildQueryWithCustomAggregator(FastR fastR) { 343 | Dplyr dplyr = new Dplyr(fastR); 344 | DplyrQueryBuilder dplyrBuilder = dplyr.newQueryBuilder(); 345 | dplyrBuilder.select("id", "name", "language"). 346 | assignAggregator("myAggr", myAggr2). 347 | group_by("language"). 348 | summarise("myaggr = myAggr(name)"); 349 | 350 | Value dplyrQuery0 = dplyrBuilder.build(); 351 | 352 | User[] data = getUsers(); 353 | Value df = fastR.asDataFrame(new UsersTable(data)); 354 | Value res = dplyrQuery0.execute(df); 355 | 356 | for (List row : asRows(res)) { 357 | System.out.println(row); 358 | } 359 | } 360 | 361 | private static void buildSimpleQuery(FastR fastR) { 362 | 363 | Dplyr dplyr = new Dplyr(fastR); 364 | 365 | Value mtcarsCylQ = dplyr.newQueryBuilder("mtcars"). 366 | group_by("cyl"). 367 | summarise("total = n()"). 368 | build(); 369 | 370 | Value mtcarsCyl = mtcarsCylQ.execute(); 371 | 372 | System.out.println(mtcarsCyl); 373 | } 374 | 375 | private static void parseSimpleParamQueryFromBundle(FastR fastR) { 376 | 377 | RBundle bundle = new RBundle(fastR, new File("src/main/resources/sampleBundle.R")); 378 | Value mtcarsCylQ = bundle.buildQuery("mtcarsCylQ"); 379 | Value mtcarsCyl = mtcarsCylQ.execute(18.5); 380 | 381 | System.out.println("cyl\ttotal"); 382 | for (List row : asRows(mtcarsCyl)) { 383 | System.out.println(row.get(0).asInt() + "\t" + row.get(1).asInt()); 384 | } 385 | 386 | } 387 | 388 | private static void parseSimpleParamQuery(FastR fastR) { 389 | 390 | fastR.require("dplyr"); 391 | 392 | Value mtcarsCylQ = fastR. 393 | asFunction("mtcars %>% filter(mpg > _mpg_) %>% group_by(cyl) %>% summarise(total = n())"); 394 | Value mtcarsCyl = mtcarsCylQ.execute(18.5); 395 | 396 | System.out.println("cyl\ttotal"); 397 | for (List row : asRows(mtcarsCyl)) { 398 | System.out.println(row.get(0).asInt() + "\t" + row.get(1).asInt()); 399 | } 400 | 401 | } 402 | 403 | private static void parseSimpleQuery(FastR fastR) { 404 | 405 | fastR.require("dplyr"); 406 | 407 | Value mtcarsCyl = fastR.eval("mtcars %>% group_by(cyl) %>% summarise(total = n())"); 408 | 409 | System.out.println("cyl\ttotal"); 410 | for (List row : asRows(mtcarsCyl)) { 411 | System.out.println(row.get(0).asInt() + "\t" + row.get(1).asInt()); 412 | } 413 | 414 | } 415 | 416 | private static void usingPackages() { 417 | FastR fastR = new FastR(); 418 | 419 | fastR.require("jsonlite"); 420 | 421 | Value rndJson = fastR.execute("toJSON", fastR.execute("runif", 10)); 422 | System.out.println(rndJson.asString()); 423 | 424 | Value intArrayJson = fastR.asFunction("toJSON(as.integer(_x_))"). 425 | execute(new int[] {1, 2, 3}); 426 | System.out.println(intArrayJson.asString()); 427 | 428 | Value userJson = fastR.asFunction("toJSON(as.list(_x_))"). 429 | execute(new User(100, "Pepa", "R")); 430 | System.out.println(userJson.asString()); 431 | 432 | fastR.installPackage("jsonlite"); 433 | 434 | if (!fastR.require("jsonlite")) { 435 | fastR.installPackage("jsonlite"); 436 | } 437 | 438 | } 439 | 440 | private static void usingJavaObjects() { 441 | @SuppressWarnings("resource") 442 | 443 | FastR fastR = new FastR(); 444 | 445 | fastR.execute("print", new User(100, "Pepa", "R")); 446 | 447 | fastR.execute("(function (user) print(user$name))", 448 | new User(100, "Pepa", "R")); 449 | 450 | Value displ = fastR.execute("(function (user) user$toDisplayName('***'))", 451 | new User(100, "Pepa", "R")); 452 | 453 | displ = fastR.asFunction("_user_$toDisplayName('***')"). 454 | execute(new User(100, "Pepa", "R")); 455 | 456 | 457 | System.out.println(displ); 458 | } 459 | 460 | private static void basicFastR() { 461 | @SuppressWarnings("resource") 462 | 463 | FastR fastR = new FastR(); 464 | Value rnd = fastR.execute("runif", 12); 465 | Value mat = fastR.call("matrix", rnd, named("nrow", 3), named("ncol", 4)); 466 | fastR.execute("print", mat); 467 | System.out.println(mat); 468 | 469 | } 470 | 471 | public interface MyStruct { int id(); String text(); List arr(); } 472 | 473 | private static void polyglotUsage2() { 474 | 475 | Context context = Context.newBuilder().allowAllAccess(true).build(); 476 | Value result = context.eval("R", "list(" + 477 | "id = 42, " + 478 | "text = '42', " + 479 | "arr = c(1,42,3)" + 480 | ")"); 481 | assert result.hasMembers(); 482 | 483 | int id = result.getMember("id").asInt(); 484 | assert id == 42; 485 | 486 | String text = result.getMember("text").asString(); 487 | assert text.equals("42"); 488 | 489 | Value array = result.getMember("arr"); 490 | assert array.hasArrayElements(); 491 | assert array.getArraySize() == 3; 492 | assert array.getArrayElement(1).asInt() == 42; 493 | 494 | MyStruct myStruct = result.as(MyStruct.class); 495 | assert myStruct.arr().size() == 3; 496 | } 497 | 498 | private static void polyglotUsage() { 499 | 500 | Context polyglot = Context.newBuilder("R"). 501 | allowAllAccess(true). 502 | build(); 503 | 504 | Value rnd = polyglot.eval("R", "runif(10)"); 505 | for (int i = 0; i < rnd.getArraySize(); i++) { 506 | System.out.println(rnd.getArrayElement(i).asDouble()); 507 | } 508 | 509 | } 510 | 511 | private static User[] getUsers() { 512 | return new User[] { 513 | new User(1, "Florian", "Python"), 514 | new User(2, "Lukas", "R"), 515 | new User(3, "Mila", "Java"), 516 | new User(4, "Paley", "Coq"), 517 | new User(5, "Stepan", "C#"), 518 | new User(6, "Tomas", "Java"), 519 | new User(7, "Zbynek", "Scala"), 520 | }; 521 | } 522 | 523 | public static class MyClass { 524 | public int id = 42; 525 | public String text = "42"; 526 | public int[] arr = new int[]{1, 42, 3}; 527 | public Callable ret42 = () -> 42; 528 | } 529 | 530 | public static void main2(String[] args) { 531 | Context context = Context.newBuilder().allowAllAccess(true).build(); 532 | context.getPolyglotBindings().putMember("javaObj", new MyClass()); 533 | boolean valid = context.eval("R", 534 | "javaObj <- import('javaObj');" + 535 | " javaObj$id == 42" + 536 | " && javaObj$text == '42'" + 537 | " && javaObj$arr[[2]] == 42" + 538 | " && javaObj$ret42() == 42") 539 | .asBoolean(); 540 | assert valid == true; 541 | } 542 | 543 | } 544 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/FastRJavaUI.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Container; 5 | import java.awt.Dimension; 6 | import java.awt.FlowLayout; 7 | import java.awt.event.ActionListener; 8 | import java.util.function.Supplier; 9 | 10 | import javax.swing.JComboBox; 11 | import javax.swing.JFrame; 12 | import javax.swing.JLabel; 13 | import javax.swing.JPanel; 14 | import javax.swing.WindowConstants; 15 | import javax.swing.border.EmptyBorder; 16 | 17 | import org.graalvm.polyglot.Context; 18 | import org.graalvm.polyglot.Value; 19 | 20 | public class FastRJavaUI { 21 | public static final class PlotParams { 22 | public final int clustersCount; 23 | public final String xVar; 24 | public final String yVar; 25 | 26 | PlotParams(int clustersCount, String xVar, String yVar) { 27 | this.clustersCount = clustersCount; 28 | this.xVar = xVar; 29 | this.yVar = yVar; 30 | } 31 | } 32 | 33 | static final class MyPlotJPanel extends PlotJPanel { 34 | private static final long serialVersionUID = -6022725592051006171L; 35 | 36 | private static final String PLOT_FN = "require(grid); require(lattice);" + "function(plotParams) { " 37 | + " print(plotParams); clustersCount <- plotParams$clustersCount; x <- plotParams$xVar; y <- plotParams$yVar;" 38 | + " iris$cluster <- factor(kmeans(iris[, c(y, x)], clustersCount)$cluster);" 39 | + " print(xyplot(as.formula(paste0(y,'~',x)), data=iris, groups=cluster, pch=20, cex=3));" + "}"; 40 | private final Supplier paramsSupplier; 41 | 42 | MyPlotJPanel(Supplier paramsSupplier) { 43 | this.paramsSupplier = paramsSupplier; 44 | } 45 | 46 | @Override 47 | protected Value getPlotFunction(Context context) { 48 | return context.eval("R", PLOT_FN); 49 | } 50 | 51 | @Override 52 | protected Object getPlotParameters() { 53 | return paramsSupplier.get(); 54 | } 55 | 56 | } 57 | 58 | // Create and set up the window -- this is standard Java/Swing 59 | private static void createAndShowGUI() { 60 | JFrame frame = new JFrame("Hello World to R from Java"); 61 | frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 62 | frame.setPreferredSize(new Dimension(750, 500)); 63 | 64 | JComboBox clustersCombo = new JComboBox<>(new Integer[] { 2, 3, 4, 5, 6, 7 }); 65 | clustersCombo.setSelectedIndex(2); 66 | String[] variables = { "Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width" }; 67 | JComboBox xAxisCombo = new JComboBox<>(variables); 68 | JComboBox yAxisCombo = new JComboBox<>(variables); 69 | yAxisCombo.setSelectedIndex(1); 70 | 71 | JPanel plot = new MyPlotJPanel(() -> new PlotParams((Integer) clustersCombo.getSelectedItem(), 72 | (String) xAxisCombo.getSelectedItem(), (String) yAxisCombo.getSelectedItem())); 73 | ActionListener updatePlot = e -> plot.repaint(); 74 | clustersCombo.addActionListener(updatePlot); 75 | xAxisCombo.addActionListener(updatePlot); 76 | yAxisCombo.addActionListener(updatePlot); 77 | 78 | JPanel options = new JPanel(); 79 | options.setLayout(new FlowLayout(FlowLayout.CENTER)); 80 | options.add(new JLabel("X Variable: ")); 81 | options.add(xAxisCombo); 82 | options.add(new JLabel("Y Variable: ")); 83 | options.add(yAxisCombo); 84 | options.add(new JLabel("Clusters count: ")); 85 | options.add(clustersCombo); 86 | xAxisCombo.setBorder(new EmptyBorder(0, 0, 0, 40)); 87 | yAxisCombo.setBorder(new EmptyBorder(0, 0, 0, 40)); 88 | clustersCombo.setBorder(new EmptyBorder(0, 0, 0, 40)); 89 | 90 | frame.setLayout(new BorderLayout(20, 20)); 91 | Container pane = frame.getContentPane(); 92 | pane.add(options, BorderLayout.PAGE_START); 93 | pane.add(plot, BorderLayout.CENTER); 94 | 95 | frame.pack(); 96 | frame.setVisible(true); 97 | } 98 | 99 | public static void main(String[] args) throws Exception { 100 | javax.swing.SwingUtilities.invokeLater(() -> createAndShowGUI()); 101 | } 102 | } -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/GraalVM.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.function.Function; 9 | import java.util.stream.Stream; 10 | import java.util.stream.StreamSupport; 11 | 12 | import org.graalvm.polyglot.Value; 13 | 14 | public final class GraalVM { 15 | 16 | private static class ValueIterable implements Iterable { 17 | 18 | private final Value arrayValue; 19 | private final long sz; 20 | 21 | private ValueIterable(Value arrayValue) { 22 | assert arrayValue.hasArrayElements(); 23 | this.arrayValue = arrayValue; 24 | this.sz = arrayValue.getArraySize(); 25 | } 26 | 27 | @Override 28 | public Iterator iterator() { 29 | return new Iterator() { 30 | 31 | long i = 0; 32 | 33 | @Override 34 | public boolean hasNext() { 35 | return i < sz; 36 | } 37 | 38 | @Override 39 | public Value next() { 40 | return arrayValue.getArrayElement(i++); 41 | } 42 | 43 | }; 44 | } 45 | }; 46 | 47 | public static Iterable asIterable(Value value) { 48 | if (value.hasArrayElements()) { 49 | return new ValueIterable(value); 50 | } else { 51 | return Collections.singleton(value); 52 | } 53 | } 54 | 55 | public static Stream asStream(Value value) { 56 | if (value.hasArrayElements()) { 57 | return StreamSupport.stream(new ValueIterable(value).spliterator(), false); 58 | } else { 59 | return Stream.of(value); 60 | } 61 | } 62 | 63 | public static Value[] asArray(Value val) { 64 | int sz = (int)val.getArraySize(); 65 | Value[] arr = new Value[sz]; 66 | for (int i = 0; i < sz; i++) { 67 | arr[i] = val.getArrayElement(i); 68 | } 69 | return arr; 70 | } 71 | 72 | public static Object[] asArray(Value val, Function mapper) { 73 | int sz = (int)val.getArraySize(); 74 | Object[] arr = new Object[sz]; 75 | for (int i = 0; i < sz; i++) { 76 | arr[i] = mapper.apply(val.getArrayElement(i)); 77 | } 78 | return arr; 79 | } 80 | 81 | public static Map asMap(Value val) { 82 | return asMap(val, x -> x); 83 | } 84 | 85 | public static Map asMap(Value val, Function mapper) { 86 | Map map = new HashMap<>(); 87 | Set keys = val.getMemberKeys(); 88 | for (String key : keys) { 89 | map.put(key, mapper.apply(val.getMember(key))); 90 | } 91 | return map; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/IrisHandler.R: -------------------------------------------------------------------------------- 1 | require(dplyr) 2 | require(ggplot2) 3 | require(kableExtra) 4 | 5 | # A sample query using dplyr and kable to generate a HTML table from the iris dataset. 6 | # Parameters: 7 | # _data_: 8 | # _len_: 9 | kableQuerySample1 <- quote(_data_ %>% 10 | mutate_if(is.numeric, function(x) { 11 | cell_spec(x, bold = T, 12 | color = spec_color(x, end = 0.9), 13 | font_size = spec_font_size(x)) 14 | }) %>% 15 | mutate(Species = cell_spec(Species, 16 | color = 'white', bold = T, 17 | background = spec_color(1:_len_, end = 0.9, option = 'A', direction = -1)) 18 | ) %>% 19 | kable(escape = F, align = 'c') %>% 20 | kable_styling(c('striped', 'condensed'), full_width = F)) 21 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/IrisHandler.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | 6 | import org.graalvm.polyglot.Value; 7 | 8 | public final class IrisHandler { 9 | 10 | private final FastR fastR; 11 | private final Value irisData; 12 | private final Value kableQuery; 13 | 14 | public IrisHandler(FastR fastR) { 15 | this.fastR = fastR; 16 | this.irisData = fastR.eval("iris"); 17 | 18 | RBundle bundle = new RBundle(fastR, IrisHandler.class); 19 | this.kableQuery = bundle.buildQuery("kableQuerySample1"); 20 | } 21 | 22 | public static IrisHandler getHandler(Map request) { 23 | return FastR.getInstance().getOrCreate(IrisHandler.class, fastR -> new IrisHandler(fastR)); 24 | } 25 | 26 | public String generateTable(int maxRows) throws IOException { 27 | Value data = fastR.execute("head", irisData, maxRows); 28 | return kableQuery.execute(data, maxRows).asString(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/PlotJPanel.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import static java.awt.image.BufferedImage.TYPE_INT_RGB; 4 | 5 | import java.awt.BorderLayout; 6 | import java.awt.Color; 7 | import java.awt.Container; 8 | import java.awt.Dimension; 9 | import java.awt.Graphics; 10 | import java.awt.Graphics2D; 11 | import java.awt.image.BufferedImage; 12 | import java.util.function.Supplier; 13 | 14 | import javax.swing.JFrame; 15 | import javax.swing.JPanel; 16 | import javax.swing.WindowConstants; 17 | 18 | import org.graalvm.polyglot.Context; 19 | import org.graalvm.polyglot.Value; 20 | 21 | public abstract class PlotJPanel extends JPanel { 22 | private static final long serialVersionUID = -7296367853334296393L; 23 | 24 | private Context context = null; 25 | private Value showPlot = null; 26 | private Value plotFunction = null; 27 | 28 | public PlotJPanel() { 29 | } 30 | 31 | public static PlotJPanel createSimplePlotPanel(FastR fastR, String plotFunctionSource, Supplier data) { 32 | return createSimplePlotPanel(fastR.getContext(), fastR.asFunction(plotFunctionSource), data); 33 | } 34 | 35 | public static PlotJPanel createSimplePlotPanel(Context context, Value plotFunction, Supplier data) { 36 | return new PlotJPanel() { 37 | private static final long serialVersionUID = -72418092687364509L; 38 | 39 | @Override 40 | protected Context getContext() { 41 | return context; 42 | } 43 | 44 | @Override 45 | protected Object getPlotParameters() { 46 | return data.get(); 47 | } 48 | 49 | @Override 50 | protected Value getPlotFunction(Context context) { 51 | return plotFunction; 52 | } 53 | }; 54 | } 55 | 56 | public static final String PLOT_REGRESSION = "function (fit) {\n" + 57 | "ggplot(fit$model, aes_string(x = names(fit$model)[2], y = names(fit$model)[1])) + \n" + 58 | " geom_point() +\n" + 59 | " stat_smooth(method = \"lm\", col = \"red\") +\n" + 60 | " labs(title = paste(\"Adj R2 = \",signif(summary(fit)$adj.r.squared, 5),\n" + 61 | " \"Intercept =\",signif(fit$coef[[1]],5 ),\n" + 62 | " \" Slope =\",signif(fit$coef[[2]], 5),\n" + 63 | " \" P =\",signif(summary(fit)$coef[2,4], 5)))\n" + 64 | "}\n"; 65 | 66 | public static PlotJPanel createRegressionPlotPanel(Context context, Supplier data) { 67 | return createSimplePlotPanel(context, context.eval("R", PLOT_REGRESSION), data); 68 | } 69 | 70 | protected Context getContext() { 71 | return Context.newBuilder("R").allowAllAccess(true).build(); 72 | } 73 | 74 | protected abstract Value getPlotFunction(Context context); 75 | 76 | protected abstract Object getPlotParameters(); 77 | 78 | public BufferedImage paintHeadless() { 79 | // Instead of drawing to a component, we use BufferedImage for headless testing 80 | // Note: one can achieve this with "png" built-in directly in R, 81 | // this is only example of what can be done 82 | int w = getWidth(); 83 | int h = getHeight(); 84 | BufferedImage image = new BufferedImage(w, h, TYPE_INT_RGB); 85 | Graphics2D graphics = (Graphics2D) image.getGraphics(); 86 | graphics.setBackground(new Color(255, 255, 255)); 87 | graphics.clearRect(0, 0, w, h); 88 | 89 | plot(graphics); 90 | 91 | return image; 92 | } 93 | 94 | @Override 95 | public void paint(Graphics g) { 96 | super.paint(g); 97 | plot(g); 98 | } 99 | 100 | private void plot(Graphics g) { 101 | if (context == null) { 102 | initMainPlotFunction(); 103 | } 104 | // The MAGIC happens HERE: we invoke R plotting code and pass it the graphics object 105 | showPlot.execute((Graphics2D) g, getWidth(), getHeight(), plotFunction, getPlotParameters()); 106 | } 107 | 108 | private Value initMainPlotFunction() { 109 | context = getContext(); 110 | plotFunction = getPlotFunction(context); 111 | // This R function opens FastR graphics device passing it Graphics2D object, 112 | // then it plots the graph and closes the device 113 | String src = "library(grid); library(lattice); " + 114 | "function(g, w, h, plotFn, plotParams) { " + 115 | " grDevices:::awt(w, h, g);" + 116 | " print(plotFn(plotParams));" + 117 | " dev.off();" + 118 | " NULL;" + 119 | "}"; 120 | showPlot = context.eval("R", src); 121 | return showPlot; 122 | } 123 | 124 | public void showFrame(String title, int width, int height) { 125 | JFrame frame = new JFrame(title); 126 | frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 127 | frame.setPreferredSize(new Dimension(width, height)); 128 | 129 | Container pane = frame.getContentPane(); 130 | pane.add(this, BorderLayout.CENTER); 131 | 132 | frame.pack(); 133 | frame.setVisible(true); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/java/com/oracle/truffle/r/fastrj/RBundle.java: -------------------------------------------------------------------------------- 1 | package com.oracle.truffle.r.fastrj; 2 | 3 | import static com.oracle.truffle.r.fastrj.FastR.named; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.net.URL; 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | 13 | import org.graalvm.polyglot.Value; 14 | 15 | public final class RBundle { 16 | 17 | private final FastR fastR; 18 | 19 | /** 20 | * An environment containing the bundle 21 | */ 22 | private final Value qenv; 23 | 24 | public RBundle(FastR fastR, Class bundleFileCompanionClass) { 25 | this.fastR = fastR; 26 | URL queryFileResource = bundleFileCompanionClass.getResource(bundleFileCompanionClass.getSimpleName() + ".R"); 27 | if (queryFileResource == null) { 28 | throw new RuntimeException("R bundle for class " + bundleFileCompanionClass.getName() + " not found"); 29 | } 30 | try (BufferedReader br = new BufferedReader(new InputStreamReader(queryFileResource.openStream()))) { 31 | String bundleSource = br.lines().collect(Collectors.joining(System.lineSeparator())); 32 | Value queries = fastR.parse(bundleSource); 33 | this.qenv = fastR.newEnvironment(); 34 | fastR.call("eval", queries, named("envir", qenv)); 35 | } catch (IOException e) { 36 | throw new RuntimeException(e); 37 | } 38 | } 39 | 40 | public RBundle(FastR fastR, File bundleFilePath) { 41 | this.fastR = fastR; 42 | Value bundle = fastR.execute("parse", bundleFilePath.getAbsolutePath()); 43 | this.qenv = fastR.newEnvironment(); 44 | fastR.call("eval", bundle, named("envir", qenv)); 45 | } 46 | 47 | public Set getQueryNames() { 48 | return qenv.getMemberKeys(); 49 | } 50 | 51 | public Value get(String name) { 52 | return fastR.execute("get", name, qenv); 53 | } 54 | 55 | public Value buildQuery(String queryName) { 56 | Value queryAST = fastR.execute("get", queryName, qenv); 57 | return fastR.asFunction(queryAST); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/js/server.js: -------------------------------------------------------------------------------- 1 | console.log("Initializing FastRJ server"); 2 | 3 | var express = require('express'); 4 | var app = express(); 5 | var BrexitHandler = Java.type('com.oracle.truffle.r.fastrj.BrexitHandler'); 6 | 7 | app.get('/brexit', function (req, res) { 8 | var handler = BrexitHandler.getHandler(req); 9 | res.contentType('image/svg+xml'); 10 | res.send(handler.plotChart(parseInt(req.query.maxCols))); 11 | }); 12 | 13 | var IrisHandler = Java.type('com.oracle.truffle.r.fastrj.IrisHandler'); 14 | app.get('/iris', function (req, res) { 15 | var handler = IrisHandler.getHandler(req); 16 | res.contentType('text/html'); 17 | res.send("" + handler.generateTable(parseInt(req.query.maxRows)) + ""); 18 | }); 19 | 20 | var port = 12836; 21 | var server = app.listen(port, function() { 22 | console.log("Server listening on http://localhost:" + port); 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/resources/msleep_ggplot2.csv: -------------------------------------------------------------------------------- 1 | name,genus,vore,order,conservation,sleep_total,sleep_rem,sleep_cycle,awake,brainwt,bodywt 2 | Cheetah,Acinonyx,carni,Carnivora,lc,12.1,NA,NA,11.9,NA,50 3 | Owl monkey,Aotus,omni,Primates,NA,17,1.8,NA,7,0.0155,0.48 4 | Mountain beaver,Aplodontia,herbi,Rodentia,nt,14.4,2.4,NA,9.6,NA,1.35 5 | Greater short-tailed shrew,Blarina,omni,Soricomorpha,lc,14.9,2.3,0.133333333,9.1,0.00029,0.019 6 | Cow,Bos,herbi,Artiodactyla,domesticated,4,0.7,0.666666667,20,0.423,600 7 | Three-toed sloth,Bradypus,herbi,Pilosa,NA,14.4,2.2,0.766666667,9.6,NA,3.85 8 | Northern fur seal,Callorhinus,carni,Carnivora,vu,8.7,1.4,0.383333333,15.3,NA,20.49 9 | Vesper mouse,Calomys,NA,Rodentia,NA,7,NA,NA,17,NA,0.045 10 | Dog,Canis,carni,Carnivora,domesticated,10.1,2.9,0.333333333,13.9,0.07,14 11 | Roe deer,Capreolus,herbi,Artiodactyla,lc,3,NA,NA,21,0.0982,14.8 12 | Goat,Capri,herbi,Artiodactyla,lc,5.3,0.6,NA,18.7,0.115,33.5 13 | Guinea pig,Cavis,herbi,Rodentia,domesticated,9.4,0.8,0.216666667,14.6,0.0055,0.728 14 | Grivet,Cercopithecus,omni,Primates,lc,10,0.7,NA,14,NA,4.75 15 | Chinchilla,Chinchilla,herbi,Rodentia,domesticated,12.5,1.5,0.116666667,11.5,0.0064,0.42 16 | Star-nosed mole,Condylura,omni,Soricomorpha,lc,10.3,2.2,NA,13.7,0.001,0.06 17 | African giant pouched rat,Cricetomys,omni,Rodentia,NA,8.3,2,NA,15.7,0.0066,1 18 | Lesser short-tailed shrew,Cryptotis,omni,Soricomorpha,lc,9.1,1.4,0.15,14.9,0.00014,0.005 19 | Long-nosed armadillo,Dasypus,carni,Cingulata,lc,17.4,3.1,0.383333333,6.6,0.0108,3.5 20 | Tree hyrax,Dendrohyrax,herbi,Hyracoidea,lc,5.3,0.5,NA,18.7,0.0123,2.95 21 | North American Opossum,Didelphis,omni,Didelphimorphia,lc,18,4.9,0.333333333,6,0.0063,1.7 22 | Asian elephant,Elephas,herbi,Proboscidea,en,3.9,NA,NA,20.1,4.603,2547 23 | Big brown bat,Eptesicus,insecti,Chiroptera,lc,19.7,3.9,0.116666667,4.3,3e-04,0.023 24 | Horse,Equus,herbi,Perissodactyla,domesticated,2.9,0.6,1,21.1,0.655,521 25 | Donkey,Equus,herbi,Perissodactyla,domesticated,3.1,0.4,NA,20.9,0.419,187 26 | European hedgehog,Erinaceus,omni,Erinaceomorpha,lc,10.1,3.5,0.283333333,13.9,0.0035,0.77 27 | Patas monkey,Erythrocebus,omni,Primates,lc,10.9,1.1,NA,13.1,0.115,10 28 | Western american chipmunk,Eutamias,herbi,Rodentia,NA,14.9,NA,NA,9.1,NA,0.071 29 | Domestic cat,Felis,carni,Carnivora,domesticated,12.5,3.2,0.416666667,11.5,0.0256,3.3 30 | Galago,Galago,omni,Primates,NA,9.8,1.1,0.55,14.2,0.005,0.2 31 | Giraffe,Giraffa,herbi,Artiodactyla,cd,1.9,0.4,NA,22.1,NA,899.995 32 | Pilot whale,Globicephalus,carni,Cetacea,cd,2.7,0.1,NA,21.35,NA,800 33 | Gray seal,Haliochoerus,carni,Carnivora,lc,6.2,1.5,NA,17.8,0.325,85 34 | Gray hyrax,Heterohyrax,herbi,Hyracoidea,lc,6.3,0.6,NA,17.7,0.01227,2.625 35 | Human,Homo,omni,Primates,NA,8,1.9,1.5,16,1.32,62 36 | Mongoose lemur,Lemur,herbi,Primates,vu,9.5,0.9,NA,14.5,NA,1.67 37 | African elephant,Loxodonta,herbi,Proboscidea,vu,3.3,NA,NA,20.7,5.712,6654 38 | Thick-tailed opposum,Lutreolina,carni,Didelphimorphia,lc,19.4,6.6,NA,4.6,NA,0.37 39 | Macaque,Macaca,omni,Primates,NA,10.1,1.2,0.75,13.9,0.179,6.8 40 | Mongolian gerbil,Meriones,herbi,Rodentia,lc,14.2,1.9,NA,9.8,NA,0.053 41 | Golden hamster,Mesocricetus,herbi,Rodentia,en,14.3,3.1,0.2,9.7,0.001,0.12 42 | Vole ,Microtus,herbi,Rodentia,NA,12.8,NA,NA,11.2,NA,0.035 43 | House mouse,Mus,herbi,Rodentia,nt,12.5,1.4,0.183333333,11.5,4e-04,0.022 44 | Little brown bat,Myotis,insecti,Chiroptera,NA,19.9,2,0.2,4.1,0.00025,0.01 45 | Round-tailed muskrat,Neofiber,herbi,Rodentia,nt,14.6,NA,NA,9.4,NA,0.266 46 | Slow loris,Nyctibeus,carni,Primates,NA,11,NA,NA,13,0.0125,1.4 47 | Degu,Octodon,herbi,Rodentia,lc,7.7,0.9,NA,16.3,NA,0.21 48 | Northern grasshopper mouse,Onychomys,carni,Rodentia,lc,14.5,NA,NA,9.5,NA,0.028 49 | Rabbit,Oryctolagus,herbi,Lagomorpha,domesticated,8.4,0.9,0.416666667,15.6,0.0121,2.5 50 | Sheep,Ovis,herbi,Artiodactyla,domesticated,3.8,0.6,NA,20.2,0.175,55.5 51 | Chimpanzee,Pan,omni,Primates,NA,9.7,1.4,1.416666667,14.3,0.44,52.2 52 | Tiger,Panthera,carni,Carnivora,en,15.8,NA,NA,8.2,NA,162.564 53 | Jaguar,Panthera,carni,Carnivora,nt,10.4,NA,NA,13.6,0.157,100 54 | Lion,Panthera,carni,Carnivora,vu,13.5,NA,NA,10.5,NA,161.499 55 | Baboon,Papio,omni,Primates,NA,9.4,1,0.666666667,14.6,0.18,25.235 56 | Desert hedgehog,Paraechinus,NA,Erinaceomorpha,lc,10.3,2.7,NA,13.7,0.0024,0.55 57 | Potto,Perodicticus,omni,Primates,lc,11,NA,NA,13,NA,1.1 58 | Deer mouse,Peromyscus,NA,Rodentia,NA,11.5,NA,NA,12.5,NA,0.021 59 | Phalanger,Phalanger,NA,Diprotodontia,NA,13.7,1.8,NA,10.3,0.0114,1.62 60 | Caspian seal,Phoca,carni,Carnivora,vu,3.5,0.4,NA,20.5,NA,86 61 | Common porpoise,Phocoena,carni,Cetacea,vu,5.6,NA,NA,18.45,NA,53.18 62 | Potoroo,Potorous,herbi,Diprotodontia,NA,11.1,1.5,NA,12.9,NA,1.1 63 | Giant armadillo,Priodontes,insecti,Cingulata,en,18.1,6.1,NA,5.9,0.081,60 64 | Rock hyrax,Procavia,NA,Hyracoidea,lc,5.4,0.5,NA,18.6,0.021,3.6 65 | Laboratory rat,Rattus,herbi,Rodentia,lc,13,2.4,0.183333333,11,0.0019,0.32 66 | African striped mouse,Rhabdomys,omni,Rodentia,NA,8.7,NA,NA,15.3,NA,0.044 67 | Squirrel monkey,Saimiri,omni,Primates,NA,9.6,1.4,NA,14.4,0.02,0.743 68 | Eastern american mole,Scalopus,insecti,Soricomorpha,lc,8.4,2.1,0.166666667,15.6,0.0012,0.075 69 | Cotton rat,Sigmodon,herbi,Rodentia,NA,11.3,1.1,0.15,12.7,0.00118,0.148 70 | Mole rat,Spalax,NA,Rodentia,NA,10.6,2.4,NA,13.4,0.003,0.122 71 | Arctic ground squirrel,Spermophilus,herbi,Rodentia,lc,16.6,NA,NA,7.4,0.0057,0.92 72 | Thirteen-lined ground squirrel,Spermophilus,herbi,Rodentia,lc,13.8,3.4,0.216666667,10.2,0.004,0.101 73 | Golden-mantled ground squirrel,Spermophilus,herbi,Rodentia,lc,15.9,3,NA,8.1,NA,0.205 74 | Musk shrew,Suncus,NA,Soricomorpha,NA,12.8,2,0.183333333,11.2,0.00033,0.048 75 | Pig,Sus,omni,Artiodactyla,domesticated,9.1,2.4,0.5,14.9,0.18,86.25 76 | Short-nosed echidna,Tachyglossus,insecti,Monotremata,NA,8.6,NA,NA,15.4,0.025,4.5 77 | Eastern american chipmunk,Tamias,herbi,Rodentia,NA,15.8,NA,NA,8.2,NA,0.112 78 | Brazilian tapir,Tapirus,herbi,Perissodactyla,vu,4.4,1,0.9,19.6,0.169,207.501 79 | Tenrec,Tenrec,omni,Afrosoricida,NA,15.6,2.3,NA,8.4,0.0026,0.9 80 | Tree shrew,Tupaia,omni,Scandentia,NA,8.9,2.6,0.233333333,15.1,0.0025,0.104 81 | Bottle-nosed dolphin,Tursiops,carni,Cetacea,NA,5.2,NA,NA,18.8,NA,173.33 82 | Genet,Genetta,carni,Carnivora,NA,6.3,1.3,NA,17.7,0.0175,2 83 | Arctic fox,Vulpes,carni,Carnivora,NA,12.5,NA,NA,11.5,0.0445,3.38 84 | Red fox,Vulpes,carni,Carnivora,NA,9.8,2.4,0.35,14.2,0.0504,4.23 85 | -------------------------------------------------------------------------------- /r_java_embedding/src/main/resources/sampleBundle.R: -------------------------------------------------------------------------------- 1 | require(dplyr) 2 | 3 | mtcarsCylQ <- quote(mtcars %>% filter(mpg > _mpg_) %>% group_by(cyl) %>% summarise(total = n())) 4 | 5 | -------------------------------------------------------------------------------- /r_java_embedding/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | set -o xtrace 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 22 | 23 | diff <(${GRAALVM_DIR}/bin/java -cp ${dir}/bin com.oracle.truffle.r.fastrembedding.FastREmbeddingDemo) ${dir}/expected.out 24 | -------------------------------------------------------------------------------- /shared_domain_logic/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'sinatra', '~> 2.2' 4 | gem 'webrick' 5 | -------------------------------------------------------------------------------- /shared_domain_logic/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | mustermann (1.1.1) 5 | ruby2_keywords (~> 0.0.1) 6 | rack (2.2.3.1) 7 | rack-protection (2.2.0) 8 | rack 9 | ruby2_keywords (0.0.5) 10 | sinatra (2.2.0) 11 | mustermann (~> 1.0) 12 | rack (~> 2.2) 13 | rack-protection (= 2.2.0) 14 | tilt (~> 2.0) 15 | tilt (2.0.10) 16 | webrick (1.7.0) 17 | 18 | PLATFORMS 19 | ruby 20 | 21 | DEPENDENCIES 22 | sinatra (~> 2.2) 23 | webrick 24 | 25 | BUNDLED WITH 26 | 2.2.32 27 | -------------------------------------------------------------------------------- /shared_domain_logic/README.md: -------------------------------------------------------------------------------- 1 | # Shared domain logic semi realistic example 2 | 3 | This example contains a small web server written in Ruby which shares a domain 4 | logic written in JS with a JS frontend GUI running in a browser. The web 5 | application consists of a web frontend with one table of people and an 6 | interactive form with live validations. 7 | 8 | ## Building & Running 9 | 10 | `export GRAALVM_DIR=.../graalvm-VERSION/` or 11 | `export GRAALVM_DIR=.../graalvm-VERSION/Content/Home` on mac. 12 | 13 | Then execute `./build.sh` to install dependencies (not necessary if you ran 14 | `../build_all.sh` beforehand) and `./run.sh` to start the web server. 15 | -------------------------------------------------------------------------------- /shared_domain_logic/THIRD_PARTY_LICENSES.TXT: -------------------------------------------------------------------------------- 1 | 2 | rack 3 | 4 | The MIT License (MIT) 5 | 6 | Copyright (C) 2007-2019 Leah Neukirchen 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to 10 | deal in the Software without restriction, including without limitation the 11 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 12 | sell copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | =============================================================================== 26 | 27 | tilt 28 | Copyright (c) 2010-2016 Ryan Tomayko 29 | 30 | The MIT license (MIT) (license text shown above) 31 | 32 | =============================================================================== 33 | 34 | Mustermann 35 | 36 | Copyright (c) 2013-2017 Konstantin Haase 37 | Copyright (c) 2016-2017 Zachary Scott 38 | 39 | The MIT license (MIT) (license text shown above) 40 | 41 | =============================================================================== 42 | 43 | rack-protection 44 | 45 | The MIT License (MIT) (license text shown above) 46 | 47 | Copyright (c) 2011-2017 Konstantin Haase 48 | Copyright (c) 2015-2017 Zachary Scott 49 | 50 | =============================================================================== 51 | 52 | sinatra 53 | 54 | The MIT License (MIT) (license text shown above) 55 | 56 | Copyright (c) 2007, 2008, 2009 Blake Mizerany 57 | Copyright (c) 2010-2017 Konstantin Haase 58 | Copyright (c) 2015-2017 Zachary Scott 59 | -------------------------------------------------------------------------------- /shared_domain_logic/app.rb: -------------------------------------------------------------------------------- 1 | require 'pp' 2 | require 'sinatra/base' 3 | 4 | # noinspection RubyConstantNamingConvention,RubyParenthesesAfterMethodCallInspection,RubyUnlessWithElseInspection 5 | class PolyglotApp < Sinatra::Base 6 | 7 | enable :static 8 | set :server, 'webrick' 9 | disable :logging 10 | 11 | PEOPLE_DB = [] 12 | 13 | def self.initialize_db 14 | PEOPLE_DB.clear 15 | PEOPLE_DB.push JsPerson.new('John', 'Doe', 50) 16 | end 17 | 18 | JS = Polyglot::InnerContext.new 19 | JS.eval('js', 'file => load(file)').call("#{__dir__}/public/person.js") 20 | JsPerson = JS.eval('js', 'Person') 21 | initialize_db 22 | 23 | def js_person_as_hash(js_user) 24 | { firstName: js_user[:firstName], 25 | lastName: js_user[:lastName], 26 | age: js_user[:age] } 27 | end 28 | 29 | get '/' do 30 | File.read(File.join(self.class.public_folder, 'index.html')) 31 | end 32 | 33 | get '/people.json' do 34 | data = PEOPLE_DB.map do |js_user| 35 | js_person_as_hash(js_user) 36 | end 37 | data.to_json 38 | end 39 | 40 | post '/person.json' do 41 | request.body.rewind # in case someone already read it 42 | person = JSON.parse request.body.read 43 | 44 | js_person = JsPerson.new(person['firstName'], person['lastName'], person['age']) 45 | js_person_is_invalid = js_person.isInvalid() 46 | if js_person_is_invalid 47 | [403, 'Invalid user.'] 48 | else 49 | PEOPLE_DB.push js_person 50 | [200, 'Ok'] 51 | end 52 | end 53 | 54 | get '/add/:times' do |times| 55 | times.to_i.times do |i| 56 | PEOPLE_DB.push JsPerson.new("John#{i}", "Doe#{i}", i % 120 + 1) 57 | end 58 | redirect '/' 59 | end 60 | 61 | get '/clean' do 62 | self.class.initialize_db 63 | redirect '/' 64 | end 65 | 66 | get '/exit' do 67 | PolyglotApp.quit! 68 | redirect '/' 69 | end 70 | end 71 | 72 | PolyglotApp.run! 73 | -------------------------------------------------------------------------------- /shared_domain_logic/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Resolve the location of this script 6 | source="${BASH_SOURCE[0]}" 7 | while [ -h "$source" ]; do 8 | prev_source="$source" 9 | source="$(readlink "$source")" 10 | if [[ "$source" != /* ]]; then 11 | # if the link was relative, it was relative to where it came from 12 | dir="$(cd -P "$(dirname "$prev_source")" && pwd)" 13 | source="$dir/$source" 14 | fi 15 | done 16 | dir="$(cd -P "$(dirname "$source")" && pwd)" 17 | 18 | set -x 19 | 20 | : "${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"}" 21 | 22 | if ! ${GRAALVM_DIR}/bin/gu list | grep '^js '; then 23 | ${GRAALVM_DIR}/bin/gu install js 24 | fi 25 | 26 | (cd "$dir" && "${GRAALVM_DIR}/bin/bundle" install) 27 | -------------------------------------------------------------------------------- /shared_domain_logic/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | People demo 4 | 22 | 23 | 24 | 25 | 26 | 27 |

Quit the application.

28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /shared_domain_logic/public/people.html: -------------------------------------------------------------------------------- 1 | 2 |

People

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 17 | 19 | 20 | 21 |
First nameLast nameAge
{ firstName }{ lastName }{ age }
22 | 23 |

New person form

24 | 25 |
26 | 27 | { this.person.errors['firstName'] } 28 |
29 | 30 | { this.person.errors['lastName'] } 31 |
32 | 33 | { this.person.errors['age'] } 34 |
35 | 36 | 37 |
38 | 39 | 79 | 80 | 85 |
86 | -------------------------------------------------------------------------------- /shared_domain_logic/public/person.js: -------------------------------------------------------------------------------- 1 | function Person(firstName, lastName, age) { 2 | this.firstName = firstName; 3 | this.lastName = lastName; 4 | this.age = Number.parseInt(age); 5 | this.errors = {}; 6 | 7 | if (!this.firstName) { 8 | this.errors.firstName = 'cannot be empty'; 9 | } 10 | if (!this.lastName) { 11 | this.errors.lastName = 'cannot be empty'; 12 | } 13 | if (Number.isNaN(this.age)) { 14 | this.errors.age = 'has to be integer'; 15 | } else { 16 | if (age < 0) { 17 | this.errors.age = 'has to be positive'; 18 | } 19 | if (age > 150) { 20 | this.errors.age = 'has to be less than 150'; 21 | } 22 | } 23 | 24 | Object.freeze(this); 25 | } 26 | 27 | Person.prototype.isInvalid = function () { 28 | return Object.keys(this.errors).length > 0; 29 | }; 30 | 31 | Person.prototype.update = function (attributes) { 32 | return new Person( 33 | ('firstName' in attributes ? attributes : this).firstName, 34 | ('lastName' in attributes ? attributes : this).lastName, 35 | ('age' in attributes ? attributes : this).age); 36 | }; 37 | 38 | Person.fromObject = function (object) { 39 | return new Person(object['firstName'], object['lastName'], object['age']) 40 | }; 41 | -------------------------------------------------------------------------------- /shared_domain_logic/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Resolve the location of this script 6 | source="${BASH_SOURCE[0]}" 7 | while [ -h "$source" ]; do 8 | prev_source="$source" 9 | source="$(readlink "$source")" 10 | if [[ "$source" != /* ]]; then 11 | # if the link was relative, it was relative to where it came from 12 | dir="$(cd -P "$(dirname "$prev_source")" && pwd)" 13 | source="$dir/$source" 14 | fi 15 | done 16 | dir="$(cd -P "$(dirname "$source")" && pwd)" 17 | 18 | : "${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"}" 19 | 20 | echo "Go to http://localhost:4567" 21 | echo "Quit the application by following the link at the bottom of the page" 22 | echo 23 | 24 | set -x 25 | 26 | "${GRAALVM_DIR}/bin/ruby" --jvm --polyglot "${dir}/app.rb" 27 | -------------------------------------------------------------------------------- /shared_domain_logic/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Resolve the location of this script 6 | source="${BASH_SOURCE[0]}" 7 | while [ -h "$source" ]; do 8 | prev_source="$source" 9 | source="$(readlink "$source")" 10 | if [[ "$source" != /* ]]; then 11 | # if the link was relative, it was relative to where it came from 12 | dir="$(cd -P "$(dirname "$prev_source")" && pwd)" 13 | source="$dir/$source" 14 | fi 15 | done 16 | dir="$(cd -P "$(dirname "$source")" && pwd)" 17 | 18 | : "${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"}" 19 | 20 | set -x 21 | 22 | "${dir}/run.sh" & 23 | 24 | url="http://localhost:4567" 25 | set +x 26 | while ! curl -s "$url/people.json"; do 27 | echo -n . 28 | sleep 1 29 | done 30 | set -x 31 | 32 | test '[{"firstName":"John","lastName":"Doe","age":50}]' = "$(curl -s "$url/people.json")" 33 | 34 | curl \ 35 | --header "Content-Type: application/json" \ 36 | --request POST \ 37 | --data '{"firstName":"Jan","lastName":"Novak","age":40}' \ 38 | http://localhost:4567/person.json 39 | 40 | test '[{"firstName":"John","lastName":"Doe","age":50},{"firstName":"Jan","lastName":"Novak","age":40}]' = "$(curl -s "$url/people.json")" 41 | 42 | curl "$url/exit" 43 | -------------------------------------------------------------------------------- /test_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | set -o xtrace 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | set -x 22 | 23 | ${dir}/weather_predictor/test.sh 24 | ${dir}/fastr_javaui/test.sh 25 | ${dir}/fastr_node/test.sh 26 | ${dir}/fastr_scalar/run.sh 27 | ${dir}/r_java_embedding/test.sh 28 | ${dir}/r_java_bench/test.sh 29 | ${dir}/shared_domain_logic/test.sh 30 | -------------------------------------------------------------------------------- /weather_predictor/README.md: -------------------------------------------------------------------------------- 1 | # Weather Predictor Application 2 | 3 | This is a demonstration of GraalVM's polyglot capabilities showing how objects and functions can be shared among different languages. 4 | 5 | The application is a simple REST service and simple web page for predicting temperature in a given city. 6 | The predictor uses a model constructed by applying linear regression to a data set consisting of temperatures in selected cities expressed as `(latitude, temperature)` tuples. 7 | The temperatures are retrieved in the Ruby part of the application via a [gem](https://rubygems.org/gems/openweather2/versions/0.1.8) wrapping [OpenWeatherMap API](http://openweathermap.org) service, while the corresponding latitudes and other cities data are retrieved from a Java class that mocks a typical data access object and can be easily extended to talk to a real database. 8 | 9 | The regression model is also built in the R module by means of the [lm](https://stat.ethz.ch/R-manual/R-devel/library/stats/html/lm.html) function. 10 | To predict the temperature in a given city the R module defines a function passing the city's latitude into the [predict](https://stat.ethz.ch/R-manual/R-devel/library/stats/html/predict.lm.html) function, which uses the model to return the predicted temperature for the given latitude. 11 | 12 | The predictor service is exposed in the JavaScript module of the application, which is designed as a simple Express.js based [Node.js](https://nodejs.org/en/) server. 13 | This module is logically divided into three stages. 14 | First, the Ruby module is loaded to initialize the OpenWeather service. 15 | Then the R module is loaded to build the prediction model. 16 | Finally, the Express.js server is launched. 17 | The server serves the web page UI at http://localhost:12836/ and one can directly query the REST API at http://localhost:12836/predict/, e.g. http://localhost:12836/predict/London. 18 | The reply to this query is a JSON object carrying the city's real and predicted temperature, such as `{"city":"London","real":6.82,"predicted":14.017807794947569}`. 19 | 20 | 21 | ## Setup 22 | 23 | Download the latest GraalVM image from the [Oracle Technology Network](http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html). 24 | Extract the archive and set the `GRAALVM_DIR` environment variable to point to the graalvm directory. 25 | 26 | Then, execute the `build.sh` script. 27 | 28 | A typical problem is proxy set-up: verify that you have the `http_proxy`, `https_proxy`, and `no_proxy` environment variables set properly. 29 | 30 | 31 | ## Run 32 | 33 | Execute the `run.sh` script and open your browser at `http://localhost:12836`. 34 | 35 | Note that `run.sh` runs the application without displaying exceptions to the terminal. 36 | It is possible to pass in arguments to enable the Chrome Inspector (`--inspect` and `--inspect.Suspend=false`) or the monitoring Agent (`--agent`). E.g. `./run.sh --inspect --inspect.Suspend=false --agent`. 37 | The `tools.sh` script enables the above mentioned tools and allows printing of exceptions to terminal. 38 | -------------------------------------------------------------------------------- /weather_predictor/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | 7 | # Resolve the location of this script 8 | source="${BASH_SOURCE[0]}" 9 | while [ -h "$source" ] ; do 10 | prev_source="$source" 11 | source="$(readlink "$source")"; 12 | if [[ "$source" != /* ]]; then 13 | # if the link was relative, it was relative to where it came from 14 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 15 | source="$dir/$source" 16 | fi 17 | done 18 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 19 | 20 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 21 | 22 | cran_mirror=http://cran.us.r-project.org 23 | if [ ! -d ${dir}/openweather ]; then 24 | echo "Cloning 'openweather'" 25 | git -C ${dir} clone https://github.com/lucasocon/openweather.git 26 | git -C ${dir}/openweather checkout d5f49d3c567bd1ac3e055a65189661d8d3851c7f 27 | fi 28 | 29 | # Install expressjs 30 | echo "Running 'npm install'" 31 | ${GRAALVM_DIR}/bin/npm --jvm --prefix ${dir} install ${dir} 32 | 33 | echo "Compiling the Java sources" 34 | mkdir -p ${dir}/bin 35 | ${GRAALVM_DIR}/bin/javac -d ${dir}/bin ${dir}/java/com/oracle/graalvm/demo/weather/*.java 36 | -------------------------------------------------------------------------------- /weather_predictor/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | set -e 7 | 8 | # Resolve the location of this script 9 | source="${BASH_SOURCE[0]}" 10 | while [ -h "$source" ] ; do 11 | prev_source="$source" 12 | source="$(readlink "$source")"; 13 | if [[ "$source" != /* ]]; then 14 | # if the link was relative, it was relative to where it came from 15 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 16 | source="$dir/$source" 17 | fi 18 | done 19 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 20 | 21 | rm -rf ${dir}/bin 22 | rm -rf ${dir}/node_modules 23 | rm -rf ${dir}/openweather 24 | -------------------------------------------------------------------------------- /weather_predictor/java/com/oracle/graalvm/demo/weather/City.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | package com.oracle.graalvm.demo.weather; 6 | 7 | public class City { 8 | private int id; 9 | private String name; 10 | private String country; 11 | private int population; 12 | private double longitude; 13 | private double lat; 14 | private double temperature; 15 | 16 | public City(int id, String name, String country, int population, double lat, double longitude, double temperature) { 17 | this.id = id; 18 | this.name = name; 19 | this.country = country; 20 | this.longitude = longitude; 21 | this.lat = lat; 22 | this.temperature = temperature; 23 | this.population = population; 24 | } 25 | 26 | public int getId() { return id; } 27 | public String getName() { return name; } 28 | public String getCountry() { return country; } 29 | public int getPopulation() { return population; } 30 | public double getLatitude() { return lat; } 31 | public double getLongitude() { return longitude; } 32 | public double getTemperature() { return temperature; } 33 | 34 | public void updateTemperature(double newValue) { 35 | temperature = newValue; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /weather_predictor/java/com/oracle/graalvm/demo/weather/CityService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | package com.oracle.graalvm.demo.weather; 6 | 7 | import java.util.Arrays; 8 | 9 | public class CityService { 10 | private static City[] cities = new City[] { 11 | new City(0, "Novovolyns'k", "Ukraine", 52720, 50.73, 24.17, 20.16), 12 | new City(1, "La Sabana", "Honduras", 1572, 15.37, -87.93, 23.58), 13 | new City(2, "Videbaek", "Denmark", 4076, 56.08, 8.63, 18.51), 14 | new City(3, "Nasirabad", "Pakistan", 28506, 27.38, 67.91, 29.46), 15 | new City(4, "Okazaki", "Japan", 355573, 34.96, 137.16, 22.01), 16 | new City(5, "Huddersfield", "UK", 149607, 53.66, -1.8, 17.24), 17 | new City(6, "Cocentaina", "Spain", 11223, 38.75, -0.44, 28), 18 | new City(7, "Ankathia", "Greece", 1300, 40.56, 22.47, 25.91), 19 | new City(8, "Mediesu Aurit", "Romania", 7062, 47.78, 23.15, 23), 20 | new City(9, "Juan Lopez", "Dominican Republic", 1547, 19.43, -70.52, 15), 21 | new City(10, "Birnin Kebbi", "Nigeria", 111883, 12.46, 4.19, 30.26), 22 | new City(11, "Chistopol", "Russia", 62020, 55.36, 50.64, 24.11), 23 | new City(12, "Periyialion", "Greece", 2120, 37.95, 22.84, 35.27), 24 | new City(13, "Togo", "Japan", 42643, 35.1, 137.04, 29), 25 | new City(14, "Shiyan", "China", 413581, 32.57, 110.78, 25.91), 26 | new City(15, "Iira", "Estonia", 138, 58.99, 24.72, 18.8), 27 | new City(16, "Ilha Soltera", "Brazil", 25305, -20.38, -51.34, 25.11), 28 | new City(17, "Ikorodu", "Nigeria", 321809, 6.61, 3.51, 28), 29 | new City(18, "Kocani", "Macedonia", 34448, 41.93, 22.4, 32.99), 30 | new City(19, "Siatista", "Greece", 5603, 40.26, 21.54, 31), 31 | new City(20, "Pella", "Greece", 2482, 40.76, 22.52, 18.56), 32 | new City(21, "Villeurbanne", "France", 132282, 45.77, 4.88, 25.73), 33 | new City(22, "Kalgoorlie-Boulder", "Australia", 37806, -30.74, 121.46, 17.69), 34 | new City(23, "Amelia", "Italy", 11886, 42.56, 12.41, 29.55), 35 | new City(24, "San Roque", "N. Mariana Islands", 1097, 15.25, 145.77, 25.26), 36 | new City(25, "'Ar'ara", "Israel", 15841, 32.49, 35.1, 31.92), 37 | new City(26, "Roshal", "Russia", 21806, 55.67, 39.88, 25.21), 38 | new City(27, "Jalaun", "India", 56651, 26.15, 79.35, 30.46), 39 | new City(28, "Huckeswagen", "Germany", 16311, 51.15, 7.34, 18.47), 40 | new City(29, "Yosu", "Korea South", 361480, 34.74, 127.74, 24.36), 41 | new City(30, "Miastko", "Poland", 10839, 54, 16.97, 16.51), 42 | new City(31, "Sao Joao da Talha", "Portugal", 19180, 38.82, -9.07, 29.48), 43 | new City(32, "Hat'", "Czech Republic", 2525, 49.95, 18.25, 21), 44 | new City(33, "Aruja", "Brazil", 75758, -23.4, -46.34, 17.78), 45 | new City(34, "Ussimae", "Estonia", 215, 59.34, 26.38, 15.71), 46 | new City(35, "Fache-Thumesnil", "France", 16113, 50.59, 3.07, 19.01), 47 | new City(36, "Hassel", "Luxembourg", 437, 49.55, 6.21, 20.75), 48 | new City(37, "Tatui", "Brazil", 95351, -23.35, -47.86, 22.16), 49 | new City(38, "Brookfield", "USA", 40323, 43.06, -88.12, 16.44), 50 | new City(39, "Bendorf", "Germany", 17637, 50.43, 7.57, 20.44), 51 | new City(40, "Kemman", "Marshall Islands", 6, 7.1, 171.57, 29), 52 | new City(41, "Subic", "Philippines", 69280, 14.88, 120.23, 24), 53 | new City(42, "Savaia", "Samoa", 395, -13.93, -171.93, 26.65), 54 | new City(43, "Savitaipale", "Finland", 4164, 61.2, 27.7, 16), 55 | new City(44, "Gandzak", "Armenia", 3823, 40.31, 45.11, 32), 56 | new City(45, "Deir Hanna", "Israel", 8551, 32.87, 35.36, 34.95), 57 | new City(46, "Sangrur", "India", 91250, 30.25, 75.84, 30.91), 58 | new City(47, "Athens", "Greece", 1649, 40.81, 22.7, 34.35), 59 | new City(48, "Csabrendek", "Hungary", 2935, 47.02, 17.3, 20.01), 60 | new City(49, "Elizabeth", "USA", 124552, 40.67, -74.19, 18.77), 61 | new City(50, "Ustrzyki Dolne", "Poland", 9608, 49.43, 22.61, 16.61), 62 | new City(51, "al-Fasir", "Sudan", 264734, 13.63, 25.35, 36.51), 63 | new City(52, "Matara", "Sri Lanka", 43346, 5.96, 80.53, 27.96), 64 | new City(53, "Barrancas", "Colombia", 17811, 10.96, -72.79, 28.46), 65 | new City(54, "Meilen", "Switzerland", 11649, 47.28, 8.63, 22.66), 66 | new City(55, "Timbauba", "Brazil", 45375, -7.5, -35.32, 27), 67 | new City(56, "Kasaoka", "Japan", 58297, 34.52, 133.52, 19.86), 68 | new City(57, "Joacaba", "Brazil", 23894, -27.17, -51.5, 21.56), 69 | new City(58, "Wahlern", "Switzerland", 6225, 46.82, 7.35, 24.14), 70 | new City(59, "Igra", "Russia", 21957, 57.56, 53.04, 23.61), 71 | new City(60, "Paistu", "Estonia", 344, 58.27, 25.62, 19), 72 | new City(61, "Ashqelon", "Israel", 107188, 31.67, 34.56, 31.71), 73 | new City(62, "Vana-Koiola", "Estonia", 104, 57.96, 27.05, 18), 74 | new City(63, "Schwechat", "Austria", 15778, 48.14, 16.5, 21.69), 75 | new City(64, "Avigliana", "Italy", 12184, 45.1, 7.38, 27.7), 76 | new City(65, "Lyskovo", "Russia", 23465, 56.03, 45.04, 20.01), 77 | new City(66, "El Cerrito", "Colombia", 38943, 3.69, -76.31, 24), 78 | new City(67, "Tyulkubas", "Kazakhstan", 12177, 42.55, 70.25, 29), 79 | new City(68, "Boynton Beach", "USA", 67720, 26.53, -80.08, 28.66), 80 | new City(69, "Yancheng", "China", 631805, 33.39, 120.12, 25.41), 81 | new City(70, "Ecully", "France", 19548, 45.77, 4.75, 25.74), 82 | new City(71, "Pasichna", "Ukraine", 4489, 48.57, 24.41, 20), 83 | new City(72, "Kazan", "Turkey", 25838, 40.23, 32.68, 25), 84 | new City(73, "Agios Thomas", "Cyprus", 31, 34.72, 32.73, 30.42), 85 | new City(74, "Gwoza", "Nigeria", 15417, 11.08, 13.7, 33.11), 86 | new City(75, "East Kilbride", "UK", 74543, 55.77, -4.18, 16.35), 87 | new City(76, "Airdrie", "UK", 35330, 55.87, -3.99, 16.33), 88 | new City(77, "Hizan", "Turkey", 16379, 38.22, 42.43, 40), 89 | new City(78, "Walhain", "Belgium", 6091, 50.62, 4.7, 17.29), 90 | new City(79, "Hulja", "Estonia", 566, 59.35, 26.21, 15.71), 91 | new City(80, "Bishop's Stortford", "UK", 39937, 51.88, 0.15, 18.08), 92 | new City(81, "Nonsan", "Korea South", 44284, 36.2, 127.09, 25.3), 93 | new City(82, "Santa Cruz do Sul", "Brazil", 108678, -29.71, -52.44, 25.91), 94 | new City(83, "Huaicheng", "China", 94801, 33.51, 119.14, 26.56), 95 | new City(84, "Kushtiya", "Bangladesh", 139580, 23.91, 89.14, 27.86), 96 | new City(85, "Wardha", "India", 114306, 20.75, 78.6, 29), 97 | new City(86, "Vigan", "Philippines", 49127, 17.56, 120.37, 22.51), 98 | new City(87, "Nagold", "Germany", 22854, 48.55, 8.73, 22.7), 99 | new City(88, "Maroslele", "Hungary", 2147, 46.27, 20.34, 25), 100 | new City(89, "East Brunswick", "USA", 48799, 40.43, -74.42, 19.87), 101 | new City(90, "Zabok", "Croatia", 2876, 46.03, 15.92, 20.26), 102 | new City(91, "Izumi", "Japan", 39126, 32.08, 130.35, 27), 103 | new City(92, "Ylamaa", "Finland", 1381, 60.8, 28, 16), 104 | new City(93, "Grado", "Spain", 10978, 43.4, -6.08, 21), 105 | new City(94, "Norodepil", "Faroe Islands", 169, 62.3, -6.52, 12), 106 | new City(95, "Schleswig", "Germany", 23945, 54.54, 9.55, 19.8), 107 | new City(96, "Cromwell", "New Zealand", 2981, -45.05, 169.23, 16.33), 108 | new City(97, "Addis 'Alem", "Ethiopia", 10088, 9.04, 38.39, 20), 109 | new City(98, "Khurja", "India", 107759, 28.26, 77.85, 30.91), 110 | new City(99, "Zhongshu", "China", 92839, 24.53, 103.76, 16.76), 111 | new City(100, "Pauastvere", "Estonia", 141, 58.67, 26.01, 18), 112 | new City(101, "Mokhotlong", "Lesotho", 9362, -29.29, 29.07, 9.86), 113 | new City(102, "Sidi Amran", "Algeria", 30906, 33.5, 6.02, 27.56), 114 | new City(103, "Carangola", "Brazil", 25480, -20.74, -42.04, 16.66), 115 | new City(104, "Thaba-Tseka", "Lesotho", 5510, -29.54, 28.6, 9.86), 116 | new City(105, "Bolshevik", "Tajikistan", 6628, 37.43, 68.68, 13.51), 117 | new City(106, "Soini", "Finland", 2647, 62.87, 24.22, 14.11), 118 | new City(107, "Laupheim", "Germany", 19128, 48.24, 9.88, 17.75), 119 | new City(108, "al-Qaysumah", "Saudi Arabia", 21060, 28.31, 46.13, 49), 120 | new City(109, "Woyang", "China", 79791, 31.99, 116.23, 23), 121 | new City(110, "Halayhay", "Philippines", 10951, 14.37, 120.81, 25), 122 | new City(111, "Khalastra", "Greece", 7373, 40.63, 22.73, 33), 123 | new City(112, "Strumica", "Macedonia", 45645, 41.43, 22.66, 27.91), 124 | new City(113, "Fengzhen", "China", 73005, 40.45, 113.14, 17.81), 125 | new City(114, "Metskula", "Estonia", 123, 58.57, 22.55, 18.67), 126 | new City(115, "Ugarcin", "Bulgaria", 2909, 43.1, 24.42, 24.01), 127 | new City(116, "Uster", "Switzerland", 28811, 47.36, 8.71, 20.79), 128 | new City(117, "Utmanzai", "Pakistan", 30177, 34.18, 71.77, 29.71), 129 | new City(118, "Phuentsholing", "Bhutan", 17884, 26.85, 89.38, 18.56), 130 | new City(119, "Bilbao", "Spain", 350782, 43.25, -2.93, 21.84), 131 | new City(120, "Bago", "Philippines", 78983, 10.55, 122.86, 26), 132 | new City(121, "Chauk", "Myanmar", 92906, 20.9, 94.82, 27.01), 133 | new City(122, "Mozonte", "Nicaragua", 2380, 13.65, -86.45, 22.51), 134 | new City(123, "Demirozu", "Turkey", 1837, 40.16, 39.89, 32), 135 | new City(124, "Kuldiga", "Latvia", 13214, 56.98, 21.95, 20), 136 | new City(125, "Pirgos", "Greece", 1142, 35, 25.15, 18), 137 | new City(126, "Malyi", "Hungary", 4110, 48.02, 20.83, 20.86), 138 | new City(127, "Braila", "Romania", 212307, 45.28, 27.97, 25), 139 | new City(128, "Centenary", "Zimbabwe", 3522, -16.8, 31.12, 21.11), 140 | new City(129, "Denny", "UK", 9493, 56.02, -3.88, 16.5), 141 | new City(130, "Havran", "Turkey", 11193, 39.56, 27.1, 31), 142 | new City(131, "Andradas", "Brazil", 27303, -22.07, -46.57, 16), 143 | new City(132, "Mjolby", "Sweden", 11504, 58.33, 15.13, 20.62), 144 | new City(133, "Grande-Saline", "Haiti", 1810, 19.25, -72.78, 26.79), 145 | new City(134, "Agua Prieta", "Mexico", 70230, 31.33, -109.56, 19), 146 | new City(135, "Idappadi", "India", 52345, 11.58, 77.85, 25.01), 147 | new City(136, "Ayodhya", "India", 54202, 26.8, 82.2, 29.31), 148 | new City(137, "Mfum", "Nigeria", 9223, 5.85, 8.8, 18.61), 149 | new City(138, "Xonobod", "Uzbekistan", 32975, 40.52, 72.38, 30), 150 | new City(139, "'Ali al Garbi", "Iraq", 20370, 32.46, 46.68, 41.71), 151 | new City(140, "Katwe", "Uganda", 5892, -0.13, 29.92, 26), 152 | new City(141, "Algete", "Spain", 18907, 40.61, -3.51, 38.38), 153 | new City(142, "Dobele", "Latvia", 11161, 56.63, 23.27, 20), 154 | new City(143, "Ilhavo", "Portugal", 17379, 40.6, -8.66, 29.71), 155 | new City(144, "Yerevan", "Armenia", 2237, 40.14, 45.19, 32), 156 | new City(145, "Rendeux", "Belgium", 2355, 50.23, 5.5, 17), 157 | new City(146, "La Motte-Servolex", "France", 13859, 45.6, 5.88, 26.48), 158 | new City(147, "Yesilhisar", "Turkey", 14491, 38.35, 35.09, 32.51), 159 | new City(148, "San Juan de Rio Coco", "Nicaragua", 3980, 13.55, -86.17, 20), 160 | new City(149, "Ponta Grossa", "Brazil", 297444, -25.09, -50.16, 19.16), 161 | new City(150, "Mataria", "Egypt", 100709, 31.17, 32.02, 18), 162 | new City(151, "Buttisholz", "Switzerland", 2923, 47.1, 8.1, 22.99), 163 | new City(152, "South Shields", "UK", 83783, 55, -1.43, 16.55), 164 | new City(153, "Patika", "Estonia", 171, 59.32, 24.91, 17), 165 | new City(154, "Kogalym", "Russia", 58694, 62.03, 74.5, 17.11), 166 | new City(155, "Schonenberg", "Switzerland", 1885, 47.2, 8.63, 23.93), 167 | new City(156, "Karavete", "Estonia", 294, 59.19, 25.75, 17), 168 | new City(157, "Florence-Graham", "USA", 63012, 33.97, -118.24, 18.76), 169 | new City(158, "Akkol", "Kazakhstan", 4266, 48.78, 53.2, 18.21), 170 | new City(159, "Tamboril", "Dominican Republic", 23753, 19.48, -70.6, 28.05), 171 | new City(160, "Sant Pere de Ribes", "Spain", 26597, 41.27, 1.77, 28.02), 172 | new City(161, "Vekso", "Denmark", 1914, 55.75, 12.25, 19.03), 173 | new City(162, "Jarmina", "Croatia", 2643, 45.32, 18.73, 23.43), 174 | new City(163, "Balingasag", "Philippines", 9878, 8.74, 124.78, 26.41), 175 | new City(164, "Yoro", "Japan", 32858, 35.31, 136.56, 24.01), 176 | new City(165, "Solone", "Ukraine", 7238, 48.22, 34.87, 25.61), 177 | new City(166, "Kralupy nad Vltavou", "Czech Republic", 17279, 50.25, 14.31, 19), 178 | new City(167, "Corsier", "Switzerland", 1700, 46.27, 6.22, 25.94), 179 | new City(168, "Bondy", "France", 48473, 48.91, 2.47, 22.33), 180 | new City(169, "Kljajicevo", "Serbia and Montenegro", 6151, 45.77, 19.28, 24), 181 | new City(170, "Eiken", "Switzerland", 1957, 47.53, 7.98, 23.43), 182 | new City(171, "Sigriswil", "Switzerland", 4328, 46.72, 7.7, 23.65), 183 | new City(172, "Salama", "Honduras", 1779, 15.75, -85.97, 24.11), 184 | new City(173, "Suceava", "Romania", 105525, 47.64, 26.26, 21), 185 | new City(174, "Pomerode", "Brazil", 22569, -26.75, -49.18, 21), 186 | new City(175, "Codo", "Brazil", 85176, -4.48, -43.88, 32.31), 187 | new City(176, "Sorata", "Bolivia", 2192, -15.79, -68.66, 18.01), 188 | new City(177, "Chik Ballapur", "India", 58529, 13.47, 77.73, 23), 189 | new City(178, "Villanueva de la Canada", "Spain", 14511, 40.45, -4, 38.37), 190 | new City(179, "Jati", "Indonesia", 87061, -6.84, 110.81, 31.11), 191 | new City(180, "Ermsdorf", "Luxembourg", 230, 49.82, 6.22, 20.19), 192 | new City(181, "Malmedy", "Belgium", 11548, 50.42, 6.03, 19.83), 193 | new City(182, "Malolos", "Philippines", 203511, 14.85, 120.81, 24.49), 194 | new City(183, "Garleni", "Romania", 6235, 46.67, 26.8, 24), 195 | new City(184, "Goeblange", "Luxembourg", 436, 49.66, 5.96, 20.17), 196 | new City(185, "Kayfan", "Kuwait", 28807, 29.32, 48.05, 46), 197 | new City(186, "Krasnogorsk", "Russia", 93079, 55.83, 37.33, 22.5), 198 | new City(187, "Saint-Louis", "Reunion", 48542, -21.27, 55.41, 31.01), 199 | new City(188, "Stayner", "Canada", 4156, 44.42, -80.08, 18), 200 | new City(189, "Habikino", "Japan", 121412, 34.56, 135.61, 27), 201 | new City(190, "Esgeran", "Azerbaijan", 1651, 39.94, 46.83, 18), 202 | new City(191, "Ashgabat", "Turkmenistan", 32144, 42.33, 59.14, 33), 203 | new City(192, "Veldhoven", "Netherlands", 42058, 51.39, 5.38, 17.78), 204 | new City(193, "Calafell", "Spain", 20247, 41.21, 1.56, 27.99), 205 | new City(194, "Salpazari", "Turkey", 10910, 40.94, 39.2, 26), 206 | new City(195, "Petite Riviere", "Mauritius", 5452, -20.18, 57.43, 23), 207 | new City(196, "Allada", "Benin", 20638, 6.65, 2.15, 29), 208 | new City(197, "Santa Rosa", "Colombia", 10683, 10.45, -75.37, 25), 209 | new City(198, "La Virtud", "Honduras", 1341, 14.05, -88.7, 26.26), 210 | new City(199, "Gecitkale", "Cyprus", 3231, 35.26, 33.73, 35.47), 211 | new City(200, "Barcelona", "Spain", 1591485, 41.4, 2.17, 27.5), 212 | new City(201, "Berlin", "El Salvador", 11492, 13.5, -88.53, 20.51), 213 | new City(202, "Berlin", "Germany", 3378275, 52.52, 13.38, 20.51), 214 | new City(203, "Brno", "Czech Republic", 365771, 49.2, 16.61, 21.25), 215 | new City(204, "Cape Town", "South Africa", 3546429, -33.93, 18.46, 14.51), 216 | new City(205, "Dublin", "Ireland", 1030431, 53.33, -6.25, 16.28), 217 | new City(206, "London", "UK", 7489022, 51.52, -0.1, 18.69), 218 | new City(207, "Los Angeles", "USA", 3911500, 34.11, -118.41, 18.84), 219 | new City(208, "Madrid", "Spain", 3146804, 40.42, -3.71, 38.37), 220 | new City(209, "New York", "USA", 8124427, 40.67, -73.94, 18.5), 221 | new City(210, "Paris", "France", 2141839, 48.86, 2.34, 22.33), 222 | new City(211, "Prague", "Czech Republic", 1168374, 50.08, 14.43, 19), 223 | new City(212, "Rome", "Italy", 2561181, 41.89, 12.5, 25.74), 224 | new City(213, "San Diego", "USA", 1299352, 32.81, -117.14, 20.54), 225 | new City(214, "San Francisco", "USA", 723724, 37.77, -122.45, 15.75), 226 | new City(215, "San Jose", "USA", 897883, 37.3, -121.85, 13.21) 227 | }; 228 | 229 | public int getTotalCount() { return cities.length; } 230 | public City[] getAll() { return cities; } 231 | public City[] getAllPaged(int skip, int pageSize) { 232 | return Arrays.stream(cities).skip(skip).limit(pageSize).toArray(n -> new City[n]); 233 | } 234 | 235 | public City findByName(String name) { 236 | System.out.println("Finding city by name " + name); 237 | return Arrays.stream(cities).filter(x -> x.getName().equals(name)).findFirst().orElse(null); 238 | } 239 | 240 | public void updateTemperature(int id, double temperature) { 241 | cities[id].updateTemperature(temperature); 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /weather_predictor/java_options: -------------------------------------------------------------------------------- 1 | java.util.logging.ConsoleHandler.level=OFF 2 | 3 | -------------------------------------------------------------------------------- /weather_predictor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weather_predictor", 3 | "version": "1.0.0", 4 | "description": "GraalVM interoperability demo", 5 | "main": "weatherServer.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "GraalVM team", 10 | "license": "Universal Permissive License (UPL)", 11 | "dependencies": { 12 | "express": "^4.15.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /weather_predictor/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | GraalVM Weather Predictor Demo 15 | 16 | 17 |
18 |

Oracle Labs   GraalVM demo

19 |
20 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
NameCountryPopulationLatitudeLongitudeTemperature
53 |
54 |
55 |
56 | 62 |
63 |
64 |
65 | 66 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /weather_predictor/public/js/script.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | // navigation between pages: 3 | $('.navbar-nav a').click(function(e) { 4 | $('.page').hide(); 5 | $('.navbar-nav .active').removeClass('active') 6 | $('#' + $(this).data('page')).show(); 7 | $(this).parent().addClass('active') 8 | e.preventDefault(); 9 | return false; 10 | }); 11 | 12 | // cities table: 13 | var citiesSkip = 0; 14 | var citiesPageSize = 10; 15 | reloadCities = function(newCitiesSkip) { 16 | citiesSkip = newCitiesSkip; 17 | var query = { limit: citiesPageSize, skip: citiesSkip }; 18 | $('.pager li').addClass('disabled'); 19 | $.get('http://localhost:12836/cities', query, function(data) { 20 | let html = ''; 21 | data.data.forEach(x => html += `${x.name}${x.country}${x.population}${x.latitude}${x.longitude}${x.temperature}`); 22 | $('#cities-table tbody').html(html); 23 | if (citiesSkip + citiesPageSize < data.totalCount) { 24 | $('.pager .next').removeClass('disabled'); 25 | } 26 | if (citiesSkip > 0) { 27 | $('.pager .previous').removeClass('disabled'); 28 | } 29 | }); 30 | }; 31 | navigationClick = function(e, elem, newCitiesSkip) { 32 | if (!$(elem).hasClass('disabled')) { 33 | reloadCities(newCitiesSkip); 34 | } 35 | e.preventDefault(); 36 | return false; 37 | }; 38 | $('.pager .previous').click(function(e) { navigationClick(e, this, citiesSkip - citiesPageSize); }); 39 | $('.pager .next').click(function(e) { navigationClick(e, this, citiesSkip + citiesPageSize); }); 40 | reloadCities(0); 41 | 42 | $('#refresh-temperatures').click(function(e) { 43 | var glyphicon = $(this).find('glyphicon'); 44 | glyphicon.addClass('glyphicon-spin'); 45 | $.post('http://localhost:12836/update-tempratures/', function() { 46 | glyphicon.removeClass('glyphicon-spin'); 47 | reloadCities(citiesSkip); 48 | }); 49 | e.preventDefault(); 50 | return false; 51 | }); 52 | 53 | // Weather prediction: 54 | var loadPlot = function() { 55 | $.get('http://localhost:12836/model-plot', function(data) { 56 | $('#plot-spinner').hide(); 57 | $('#plot').html(data).show(); 58 | }); 59 | }; 60 | loadPlot(); 61 | 62 | $('#regenerate').click(function(e) { 63 | $('.viz').hide(); 64 | $('.viz-spinner').show(); 65 | $('.action-button').prop('disabled', true); 66 | $.post('http://localhost:12836/regenerate/' + $('#model-size').val(), function() { 67 | loadPlot(); 68 | $('.action-button').prop('disabled', false); 69 | }); 70 | e.preventDefault(); 71 | return false; 72 | }); 73 | 74 | $('#predict').click(function(e) { 75 | $('#not-found').hide(); 76 | $('#prediction').hide(); 77 | $.get('http://localhost:12836/predict/' + $('#cityName').val(), function(data) { 78 | $('#result-predicted').text(data.predicted); 79 | $('#result-real').text(data.real); 80 | $('#result-loaded').text(data.loaded); 81 | $('#prediction').show(); 82 | }).fail(function() { 83 | $('#not-found').show(); 84 | }); 85 | e.preventDefault(); 86 | return false; 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /weather_predictor/public/script.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | * This file is made available under version 3 of the GNU General Public License. 4 | */ 5 | $(document).ready(function() { 6 | // navigation between pages: 7 | $('.navbar-nav a').click(function(e) { 8 | $('.page').hide(); 9 | $('.navbar-nav .active').removeClass('active') 10 | $('#' + $(this).data('page')).show(); 11 | $(this).parent().addClass('active') 12 | e.preventDefault(); 13 | return false; 14 | }); 15 | 16 | // cities table: 17 | var citiesSkip = 0; 18 | var citiesPageSize = 10; 19 | reloadCities = function(newCitiesSkip) { 20 | citiesSkip = newCitiesSkip; 21 | var query = { limit: citiesPageSize, skip: citiesSkip }; 22 | $('.pager li').addClass('disabled'); 23 | $.get('http://localhost:12836/cities', query, function(data) { 24 | let html = ''; 25 | data.data.forEach(x => html += `${x.name}${x.country}${x.population}${x.latitude}${x.longitude}${x.temperature}`); 26 | $('#cities-table tbody').html(html); 27 | if (citiesSkip + citiesPageSize < data.totalCount) { 28 | $('.pager .next').removeClass('disabled'); 29 | } 30 | if (citiesSkip > 0) { 31 | $('.pager .previous').removeClass('disabled'); 32 | } 33 | }); 34 | }; 35 | navigationClick = function(e, elem, newCitiesSkip) { 36 | if (!$(elem).hasClass('disabled')) { 37 | reloadCities(newCitiesSkip); 38 | } 39 | e.preventDefault(); 40 | return false; 41 | }; 42 | $('.pager .previous').click(function(e) { navigationClick(e, this, citiesSkip - citiesPageSize); }); 43 | $('.pager .next').click(function(e) { navigationClick(e, this, citiesSkip + citiesPageSize); }); 44 | reloadCities(0); 45 | 46 | $('#refresh-temperatures').click(function(e) { 47 | var glyphicon = $(this).find('glyphicon'); 48 | glyphicon.addClass('glyphicon-spin'); 49 | $.post('http://localhost:12836/update-tempratures/', function() { 50 | glyphicon.removeClass('glyphicon-spin'); 51 | reloadCities(citiesSkip); 52 | }); 53 | e.preventDefault(); 54 | return false; 55 | }); 56 | 57 | // Weather prediction: 58 | var loadPlot = function() { 59 | $.get('http://localhost:12836/model-plot', function(data) { 60 | $('#plot-spinner').hide(); 61 | $('#plot').html(data).show(); 62 | }); 63 | }; 64 | loadPlot(); 65 | 66 | $('#regenerate').click(function(e) { 67 | $('.viz').hide(); 68 | $('.viz-spinner').show(); 69 | $('.action-button').prop('disabled', true); 70 | $.post('http://localhost:12836/regenerate/' + $('#model-size').val(), function() { 71 | loadPlot(); 72 | $('.action-button').prop('disabled', false); 73 | }); 74 | e.preventDefault(); 75 | return false; 76 | }); 77 | 78 | $('#predict').click(function(e) { 79 | $('#not-found').hide(); 80 | $('#prediction').hide(); 81 | $.get('http://localhost:12836/predict/' + $('#cityName').val(), function(data) { 82 | $('#result-predicted').text(data.predicted); 83 | $('#result-real').text(data.real); 84 | $('#prediction').show(); 85 | }).fail(function() { 86 | $('#not-found').show(); 87 | }); 88 | e.preventDefault(); 89 | return false; 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /weather_predictor/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | 6 | # Resolve the location of this script 7 | source="${BASH_SOURCE[0]}" 8 | while [ -h "$source" ] ; do 9 | prev_source="$source" 10 | source="$(readlink "$source")"; 11 | if [[ "$source" != /* ]]; then 12 | # if the link was relative, it was relative to where it came from 13 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 14 | source="$dir/$source" 15 | fi 16 | done 17 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 18 | 19 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 20 | 21 | # Completely silent execution not reporting any exceptions/errors from Graal 22 | # It is possible to specify --inspect and --inspect.Suspend=false and/or --agent as arguments 23 | ${GRAALVM_DIR}/bin/node ${GRAALVM_ADDITIONAL_ARGS} --jvm --vm.Xss2m --vm.Dgraal.CompilationFailureAction=Silent --vm.Djava.util.logging.config.file=${dir}/java_options --vm.classpath=${dir}/bin --ruby.load-paths=${dir}/openweather/lib,${dir} --polyglot "$@" ${dir}/weatherServer.js 24 | -------------------------------------------------------------------------------- /weather_predictor/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. 3 | # This file is made available under version 3 of the GNU General Public License. 4 | 5 | set -e 6 | 7 | # Resolve the location of this script 8 | source="${BASH_SOURCE[0]}" 9 | while [ -h "$source" ] ; do 10 | prev_source="$source" 11 | source="$(readlink "$source")"; 12 | if [[ "$source" != /* ]]; then 13 | # if the link was relative, it was relative to where it came from 14 | dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" 15 | source="$dir/$source" 16 | fi 17 | done 18 | dir="$( cd -P "$( dirname "$source" )" && pwd )" 19 | 20 | : ${GRAALVM_DIR?"GRAALVM_DIR must point to a GraalVM image"} 21 | 22 | exec 3< <(${GRAALVM_DIR}/bin/node ${GRAALVM_ADDITIONAL_ARGS} --jvm --vm.classpath=${dir}/bin --ruby.load-paths=${dir}/openweather/lib,${dir} --polyglot ${dir}/weatherServer.js) 23 | 24 | while read line; do 25 | echo "$line" 26 | if grep -q 'Server listening' <<< $line; then 27 | break 28 | fi 29 | done <&3 30 | 31 | port=12836 32 | 33 | function stop() { 34 | curl -s --noproxy localhost --request GET http://localhost:${port}/exit >/dev/null 35 | } 36 | 37 | # $1 message 38 | # $2 path to GET 39 | # $3 validation string 40 | function test() { 41 | echo "$1" 42 | response=`curl -s --include --noproxy localhost --request GET http://localhost:${port}/$2 2>&1` 43 | if ! echo "$response" | grep "$3" 2>&1 >/dev/null; then 44 | echo "ERROR" 45 | echo "$response" 46 | echo 47 | stop 48 | while read line; do 49 | echo "$line" 50 | done <&3 51 | exit 1 52 | fi 53 | } 54 | 55 | echo -e "Testing GraalVM weather predictor example running at http://localhost:${port}\n" 56 | 57 | test "getting index.html" "index.html" "200 OK" 58 | test "getting prediction for London" "predict/London" "200 OK" 59 | test "getting svg visualization" "model-plot" " res.send(plotModel(model))); 94 | 95 | var port = 12836; 96 | app.use(express.static(__dirname + "/public")); 97 | var server = app.listen(port, function() { 98 | console.log("Server listening on http://localhost:" + port); 99 | }); 100 | 101 | app.get('/exit', function(req, res) { 102 | res.status(200).send(''); 103 | server.close(); 104 | }); 105 | --------------------------------------------------------------------------------