oracle.CubistOracle.common.CubistOracle.java Source code

Java tutorial

Introduction

Here is the source code for oracle.CubistOracle.common.CubistOracle.java

Source

/*
 *
 *  * INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigao e Desevolvimento em Lisboa
 *  * Copyright 2013 INESC-ID and/or its affiliates and other
 *  * contributors as indicated by the @author tags. All rights reserved.
 *  * See the copyright.txt in the distribution for a full listing of
 *  * individual contributors.
 *  *
 *  * This is free software; you can redistribute it and/or modify it
 *  * under the terms of the GNU Lesser General Public License as
 *  * published by the Free Software Foundation; either version 3.0 of
 *  * the License, or (at your option) any later version.
 *  *
 *  * This software is distributed in the hope that it will be useful,
 *  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  * Lesser General Public License for more details.
 *  *
 *  * You should have received a copy of the GNU Lesser General Public
 *  * License along with this software; if not, write to the Free
 *  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 *  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 *
 */

package oracle.CubistOracle.common;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Arrays;

/**
 * @author Diego Didona, didona@gsd.inesc-id.pt Date: 29/10/12
 */
public abstract class CubistOracle implements Oracle {
    protected static final String DATA = ".data";
    protected static final String MODEL = ".model";
    protected final static Log log = LogFactory.getLog(CubistOracle.class);
    protected final static boolean t = log.isTraceEnabled();
    protected final static Object monitor = new Object();
    protected String pathToCubist;
    protected CubistConfig cubistConfig;
    private File trainingSet;
    private PrintWriter trainingSetWriter;

    public CubistOracle(CubistConfig config, boolean buildModel) throws OracleException {
        this.cubistConfig = config;
        init(buildModel);
    }

    private void init(boolean buildModel) throws OracleException {
        pathToCubist = cubistConfig.getPathToCubist();
        if (t)
            log.trace("Successfully set the path to cubist to " + pathToCubist);
        if (buildModel)
            buildModel();
        else
            loadModel();

    }

    private void buildModel() throws OracleException {
        if (t)
            log.trace("Building a new model for targetFeature " + cubistConfig.getTargetFeature());

        if (!OracleUtil.fileExists(pathToCubist + "/cubist"))
            throw new OracleException(pathToCubist + " not found");
        if (cubistConfig.getTrainingSet() == null)
            throw new OracleException("You cannot build a model without training set");
        if (trainingSet == null) {
            trainingSet = new File(pathToCubist + "/" + cubistConfig.getTrainingSet());
            if (t)
                log.trace("setting training set to " + trainingSet.getAbsolutePath());
        }
        if ((!trainingSet.exists() || trainingSet.length() == 0))
            throw new OracleException("You need a non-empty training set to build a new model");
        String builtModel;
        if (t)
            log.trace("Going to create " + cubistConfig.getTargetFeature() + MODEL);
        builtModel = createCubistModel(cubistConfig.getTargetFeature());
        if (builtModel == null)
            throw new OracleException("Impossible to build model!");
        if (t)
            log.trace("PostModelCreation to go");
        synchronized (monitor) {
            postModelCreation(pathToCubist + "/" + cubistConfig.getTargetFeature());
        }
    }

    private void loadModel() throws OracleException {
        String builtModel;
        builtModel = cubistConfig.getModel();
        if (t)
            log.trace("Loading model " + builtModel);
        if (builtModel != null) { //if you don't want to build the model yet, do not init it!
            if (t)
                log.trace("PostModelCreation to go");
            synchronized (monitor) {
                postModelCreation(pathToCubist + "/" + cubistConfig.getTargetFeature());
            }
        } else
            throw new OracleException("You asked to load a model for " + cubistConfig.getTargetFeature()
                    + ", but the model is not there");
    }

    protected abstract void postModelCreation(String pathToModel) throws OracleException;

    /**
     * @param features
     * @param target
     * @param init     if true, you rebuild the model after having added the point
     * @throws OracleException
     */
    public void addPoint(String features, String target, boolean init) throws OracleException {
        if (trainingSet == null) {
            trainingSet = new File(pathToCubist + "/" + cubistConfig.getTrainingSet());
            if (t)
                log.trace("setting training set to " + trainingSet.getAbsolutePath());
        }
        if (trainingSetWriter == null) {
            try {
                trainingSetWriter = new PrintWriter(trainingSet);
            } catch (FileNotFoundException e) {
                throw new OracleException(e.getMessage());
            }
        }
        trainingSetWriter.println(features);
        trainingSetWriter.flush();
        if (init)
            buildModel();
    }

    public void addPoint(String features, boolean init) throws OracleException {
        addPoint(features, this.cubistConfig.getTargetFeature(), init);
    }

    public void removePoint(String features, String target) {
        throw new RuntimeException("removePoint method not supported yet");
    }

    private String[] buildCommand(String filestem) {
        StringBuilder sb = new StringBuilder();
        sb.append(this.pathToCubist).append("/cubist");
        sb.append(";");
        sb.append("-f");
        sb.append(pathToCubist).append("/").append(filestem);
        int instances = cubistConfig.getNumInstances();
        int committee = cubistConfig.getCommittee();
        if (cubistConfig.isInstancesAndRules()) {
            sb.append(";");
            sb.append("-i");
        }
        if (instances > 0) {
            sb.append(";");
            sb.append("-n");
            sb.append(instances);
        }
        if (committee > 0) {
            sb.append(";");
            sb.append("-C");
            sb.append(committee);
        }
        return sb.toString().split(";");

    }

    /**
     * Following https://www.securecoding.cert.org/confluence/display/java/FIO07-J.+Do+not+let+external+processes+block+on+IO+buffers
     * I am going to rewrite this
     *
     * @param filestem
     * @return
     */

    private String createCubistModel(String filestem) {
        try {
            String[] command = buildCommand(filestem);
            ProcessBuilder pb = new ProcessBuilder(command);
            if (t)
                log.trace("Invoking " + Arrays.toString(command));
            pb = pb.redirectErrorStream(true);
            Process p = pb.start();
            StringBuffer printErr = new StringBuffer();
            StringBuffer printOut = new StringBuffer();

            // Any error message?
            StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), System.err, printErr, true);

            // Any output?
            StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), System.out, printOut, t);

            errorGobbler.start();
            //if (t) {
            outputGobbler.start();
            //}

            int exitVal = p.waitFor();

            errorGobbler.join(); // Handle condition where the process ends before the threads finish
            //if (t) {
            outputGobbler.join();
            //}

            if (printErr.length() != 0) {
                throw new RuntimeException(printErr.toString());
            }
            if (cubistConfig.isPrintModelOnBuild()) {
                printOutputBuild(p);
            }
            p.destroy();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Could not create CubistModel " + e.getMessage());
        }
        return modelString();
    }

    private String _blocking_createCubistModel(String filestem) {
        try {
            String[] command = buildCommand(filestem);
            if (t)
                log.trace("Invoking " + Arrays.toString(command));
            Process p = Runtime.getRuntime().exec(buildCommand(filestem));
            p.waitFor();
            checkForError(p);
            if (cubistConfig.isPrintModelOnBuild()) {
                printOutputBuild(p);
            }
            p.destroy();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Could not create CubistModel " + e.getMessage());
        }
        return modelString();
    }

    private void printOutputBuild(Process p) throws OracleException {
        try {
            BufferedReader stdin = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String out;
            while ((out = stdin.readLine()) != null) {
                if (log.isTraceEnabled())
                    log.trace(out);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new OracleException(e.getMessage());
        }
    }

    private String modelString() {
        String modelString = cubistConfig.getPathToCubist() + "/" + cubistConfig.getTargetFeature() + MODEL;
        if (t)
            log.trace("Returning new model " + modelString);
        return modelString;
    }

    protected void _blocking_checkForError(Process p) throws OracleException {
        BufferedReader stderr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        String read;

        StringBuilder errorString = null;
        try {
            while ((read = stderr.readLine()) != null) {
                if (errorString == null)
                    errorString = new StringBuilder();
                errorString.append(read);
                System.out.println(read);
            }
        } catch (IOException e) {
            e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
            throw new OracleException(e.getMessage());
        }
        if (errorString != null)
            throw new OracleException((read));
    }

    protected void checkForError(Process p) throws OracleException {
        BufferedReader stderr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        String read;

        StringBuilder errorString = null;
        try {
            while ((read = stderr.readLine()) != null) {
                if (errorString == null)
                    errorString = new StringBuilder();
                errorString.append(read);
                System.out.println(read);
            }
        } catch (IOException e) {
            e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
            throw new OracleException(e.getMessage());
        }
        if (errorString != null)
            throw new OracleException((read));
    }

    @Override
    public final double query(String features) throws OracleException {
        synchronized (monitor) {
            String model = pathToCubist + "/" + cubistConfig.getTargetFeature();
            try {
                preQuery(model);
                return query(features, cubistConfig.getTargetFeature());
            } finally {
                postQuery(model);
            }
        }
    }

    @Override
    public final double[] queryWithError(String features) throws OracleException {
        synchronized (monitor) {
            String model = pathToCubist + "/" + cubistConfig.getTargetFeature();
            try {
                preQuery(model);
                return queryWithError(features, cubistConfig.getTargetFeature());
            } finally {
                postQuery(model);
            }
        }
    }

    protected abstract void preQuery(String s);

    protected abstract void postQuery(String s);

    protected abstract double query(String features, String target) throws OracleException;

    protected abstract double[] queryWithError(String features, String target) throws OracleException;

    public File getTrainingSet() {
        return trainingSet;
    }

    public File getModelFile() {
        return new File(this.pathToCubist + "/" + cubistConfig.getTargetFeature() + MODEL);
    }

    private class StreamGobbler extends Thread {
        private final InputStream is;
        private final PrintStream os;
        private final StringBuffer stringBuffer;
        private final boolean print;

        StreamGobbler(InputStream is, PrintStream os, StringBuffer sb, boolean print) {
            this.is = is;
            this.os = os;
            this.stringBuffer = sb;
            this.print = print;
        }

        /**
         * http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2 It is important that
         * the stream produced by the process are consumed, in order to avoid blocks However, we do not necessarily want
         * the stream to be printed, do we? :)
         */
        public void run() {
            try {
                int c;
                while ((c = is.read()) != -1) {
                    if (print) {
                        os.print((char) c);
                        stringBuffer.append(c);
                    }
                }
            } catch (IOException x) {
                // handle error
            }
        }
    }

}