fi.vtt.RVaadin.RImageSource.java Source code

Java tutorial

Introduction

Here is the source code for fi.vtt.RVaadin.RImageSource.java

Source

/*
* Copyright 2013 VTT Technical Research Centre of Finland
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package fi.vtt.RVaadin;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.concurrent.Semaphore;

import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;

import com.vaadin.server.StreamResource;

/**
 * RImageSource wraps the R graphics generated by Rserve into a
 * StreamResource.StreamSource object to be used with Vaadin. See The Book of
 * Vaadin for more details (under Section Stream Resources) and the
 * 'PlotDemo.java' example from the Rserve source package.
 * 
 * @author Arho Virkki
 */

@SuppressWarnings("serial")
public class RImageSource implements StreamResource.StreamSource {

    private RConnection rc;
    private String RPlotCall;

    /* Plot geometry */
    private int width = 500;
    private int height = 500;

    /* Semaphore reference for not calling R simultaneously */
    private Semaphore semaphore = null;

    /* Image type */
    String device = "png";

    /**
     * Construct the SteamSource for given R connection and plot command, and
     * fine-tune the device size with additional parameters.
     * 
     * @param rc
     *            The R connection
     * @param RPlotCall
     *            The string to contain the plot call
     * @param width
     *            Width of the plot
     * @param height
     *            Height of the plot
     * @param Semaphore
     *            to restrict the R access to one thread
     * @param device
     *            Device type ("png", "pdf",...)
     * 
     */
    public RImageSource(RConnection rc, String RPlotCall, int width, int height, Semaphore semaphore,
            String device) {

        this.rc = rc;
        this.RPlotCall = RPlotCall;
        this.width = width;
        this.height = height;
        this.semaphore = semaphore;
        this.device = device;
    }

    /* The method which returns the R graphics as a stream */
    public InputStream getStream() {
        try {

            semaphore.acquire();
            // System.out.println("Semaphore acquired");
            // System.out.flush();

            /* The R Cairo package is used for high-quality graphics */
            boolean CairoOK = rc.parseAndEval("suppressWarnings(require('Cairo',quietly=TRUE))").asInteger() > 0;
            if (!CairoOK) {
                System.err.println("RVaadin: Could not find Cairo package");
                rc.parseAndEval("cat('RVaadin: Error: " + "Could not find Cairo package.\n')");
            }

            /*
             * Observe the usage of R's try and error mechanism in Java, and
             * remember that device == 'png', 'pdf', ...
             */
            REXP xp = rc.parseAndEval("try(Cairo" + device.toUpperCase() + "('tmp." + device + "', " + "width="
                    + width + ", height=" + height + "))");

            if (xp.inherits("try-error")) {

                System.err.println("Can't open " + device + " graphics device:\n" + xp.asString());
                /* Plot the first warning into the error console */
                REXP w = rc.eval("if (exists('last.warning') && " + "length(last.warning)>0) "
                        + "names(last.warning)[1] else 0");
                if (w.isString()) {
                    System.err.println(w.asString());
                }
            }

            /*
             * Now, state the actual plot command and then close the Cairo
             * device to produce the graphics
             */
            rc.parseAndEval(RPlotCall);
            rc.parseAndEval("dev.off()");

            /*
             * The author of RServe claims that there is no I/O API for REngine
             * as it's actually more efficient to use R.
             */

            String fileName = "tmp." + device;

            xp = rc.parseAndEval("r <- readBin('" + fileName + "','raw', file.info('" + fileName + "')$size); "
                    + "unlink('" + fileName + "'); r");

            return new ByteArrayInputStream(xp.asBytes());

        } catch (RserveException rse) {
            /* RserveException (transport layer - e.g. Rserve is not running */
            System.out.println(rse);
            return null;

        } catch (REXPMismatchException mme) {
            /* REXP mismatch exception (we got something else as expected) */
            System.out.println(mme);
            mme.printStackTrace();
            return null;

        } catch (Exception e) {
            /* something else */
            System.err.println("Errors in RPLotCall: " + e.getMessage());
            e.printStackTrace();
            return null;

        } finally {
            semaphore.release();
            // System.out.println("Semaphore released");
            // System.out.flush();
        }
    }
}