org.obiba.rserver.service.RServerService.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.rserver.service.RServerService.java

Source

/*
 * Copyright (c) 2014 OBiBa. All rights reserved.
 *
 * This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.obiba.rserver.service;

import java.io.File;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.obiba.rserver.RProperties;
import org.obiba.rserver.Resources;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.google.common.collect.Lists;

/**
 * Service to manage RServer process.
 */
@Component
public class RServerService implements RServerState {

    private static final Logger log = LoggerFactory.getLogger(RServerService.class);

    @Autowired
    @SuppressWarnings("SpringJavaAutowiringInspection")
    private RProperties properties;

    private int rserveStatus = -1;

    @Override
    public Integer getPort() {
        return Resources.getRservePort();
    }

    @Override
    public String getEncoding() {
        return Resources.getRserveEncoding();
    }

    @Override
    public boolean isRunning() {
        return rserveStatus == 0;
    }

    @PostConstruct
    public void start() {

        if (rserveStatus == 0) {
            log.error("RServerService is already running");
            return;
        }

        log.info("Start RServerService with {}", properties);

        // fresh start, try to kill any remains of R server
        try {
            newRConnection().shutdown();
        } catch (Exception e) {
            // ignore
        }

        try {
            // launch the Rserve daemon and wait for it to complete
            Process rserve = buildRProcess().start();
            rserveStatus = rserve.waitFor();
            if (rserveStatus == 0) {
                log.info("R server started");
            } else {
                log.error("R server start failed with status: {}", rserveStatus);
                rserveStatus = -1;
            }
        } catch (Exception e) {
            log.warn("R server start failed", e);
            rserveStatus = -1;
        }
    }

    @PreDestroy
    public void stop() {
        if (rserveStatus != 0)
            return;

        try {
            log.info("Shutting down R server...");
            newConnection().shutdown();
            rserveStatus = -1;
            log.info("R server shut down");
            File workDir = getWorkingDirectory();
            for (File file : workDir.listFiles()) {
                delete(file);
            }
        } catch (Exception e) {
            log.error("R server shutdown failed", e);
        }
    }

    /**
     * Creates a new connection to R server.
     *
     * @return
     */
    public RConnection newConnection() {
        try {
            return newRConnection();
        } catch (RserveException e) {
            log.error("Error while connecting to R: {}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    //
    // Private methods
    //

    /**
     * Create a new RConnection given the R server settings.
     *
     * @return
     * @throws RserveException
     */
    private RConnection newRConnection() throws RserveException {
        RConnection conn = new RConnection();

        if (conn.needLogin()) {
            Map<String, String> conf = Resources.getRservConf();
            if (conf.containsKey("auth") && conf.get("auth").equals("required") && conf.containsKey("pwdfile")) {
                Map<String, String> pwds = Resources.getUsernamePasswords(conf.get("pwdfile"));
                if (!pwds.isEmpty()) {
                    Map.Entry<String, String> entry = pwds.entrySet().iterator().next();
                    conn.login(entry.getKey(), entry.getValue());
                }
            }
        }

        conn.setStringEncoding(Resources.getRserveEncoding());

        return conn;
    }

    private ProcessBuilder buildRProcess() {
        List<String> args = getArguments();
        log.info("Starting R server: {}", StringUtils.collectionToDelimitedString(args, " "));
        ProcessBuilder pb = new ProcessBuilder(args);
        pb.directory(getWorkingDirectory());
        pb.redirectErrorStream(true);
        pb.redirectOutput(ProcessBuilder.Redirect.appendTo(getRserveLogFile()));
        return pb;
    }

    private List<String> getArguments() {
        StringBuffer rserveArgs = new StringBuffer("--vanilla");
        File workDir = getWorkingDirectory();
        rserveArgs.append(" --RS-workdir ").append(workDir.getAbsolutePath());

        File conf = Resources.getRservConfFile();
        if (conf.exists()) {
            rserveArgs.append(" --RS-conf ").append(conf.getAbsolutePath());
        }

        List<String> args = Lists.newArrayList(properties.getExec(), "-e",
                "library(Rserve) ; Rserve(args='" + rserveArgs + "')");

        return args;
    }

    private void delete(File file) {
        if (file.isDirectory()) {
            for (File f : file.listFiles()) {
                delete(f);
            }
        }
        if (!file.isDirectory() || file.list().length == 0) {
            if (!file.delete()) {
                log.warn("Unable to delete file: " + file.getAbsolutePath());
            }
        }
    }

    private File getWorkingDirectory() {
        File dir = new File(Resources.getRServerHomeDir(), "work" + File.separator + "R");
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                log.error("Unable to create: {}", dir.getAbsolutePath());
            }
        }
        return dir;
    }

    private File getRserveLogFile() {
        File logFile = new File(Resources.getRServerHomeDir(), "logs" + File.separator + "Rserve.log");
        if (!logFile.getParentFile().exists()) {
            if (!logFile.getParentFile().mkdirs()) {
                log.error("Unable to create: {}", logFile.getParentFile().getAbsolutePath());
            }
        }
        return logFile;
    }

}