edu.uthscsa.ric.papaya.builder.Builder.java Source code

Java tutorial

Introduction

Here is the source code for edu.uthscsa.ric.papaya.builder.Builder.java

Source

package edu.uthscsa.ric.papaya.builder;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;

import com.yahoo.platform.yui.compressor.CssCompressor;
import com.yahoo.platform.yui.compressor.JavaScriptCompressor;

public class Builder {

    private boolean useSample;
    private boolean useAtlas;
    private boolean isLocal;
    private boolean printHelp;
    private boolean useImages;
    private boolean singleFile;
    private boolean useParamFile;
    private boolean useTitle;
    private Options options;
    private File projectDir;
    private String buildVersion;
    private int buildNumber;

    public static final String ARG_SAMPLE = "sample";
    public static final String ARG_LOCAL = "local";
    public static final String ARG_HELP = "help";
    public static final String ARG_ROOT = "root";
    public static final String ARG_ATLAS = "atlas";
    public static final String ARG_IMAGE = "images";
    public static final String ARG_SINGLE = "singlefile";
    public static final String ARG_PARAM_FILE = "parameterfile";
    public static final String ARG_TITLE = "title";
    public static final String CLI_PROGRAM_NAME = "papaya-builder";
    public static final String OUTPUT_DIR = "build";
    public static final String OUTPUT_JS_FILENAME = "papaya.js";
    public static final String OUTPUT_CSS_FILENAME = "papaya.css";
    public static final String BUILD_PROP_FILE = "build.properties";
    public static final String BUILD_PROP_PAPAYA_VERSION_ID = "PAPAYA_VERSION_ID";
    public static final String BUILD_PROP_PAPAYA_BUILD_NUM = "PAPAYA_BUILD_NUM";
    public static final String CSS_BLOCK = "<!-- CSS GOES HERE -->";
    public static final String JS_BLOCK = "<!-- JS GOES HERE -->";
    public static final String PARAM_BLOCK = "<!-- PARAMS GO HERE -->";
    public static final String TITLE_BLOCK = "<!-- TITLE GOES HERE -->";
    public static final String PAPAYA_BLOCK = "<!-- PAPAYA GOES HERE -->";
    public static final String[] JS_FILES = { "lib/jquery.js", "lib/base64-binary.js", "lib/bowser.js",
            "lib/daikon.js", "lib/numerics.js", "lib/pako-inflate.js", "src/js/constants.js",
            "src/js/utilities/array-utils.js", "src/js/utilities/math-utils.js", "src/js/utilities/object-utils.js",
            "src/js/utilities/platform-utils.js", "src/js/utilities/string-utils.js",
            "src/js/utilities/url-utils.js", "src/js/core/coordinate.js", "src/js/core/point.js",
            "src/js/volume/header.js", "src/js/volume/imagedata.js", "src/js/volume/imagedescription.js",
            "src/js/volume/imagedimensions.js", "src/js/volume/imagerange.js", "src/js/volume/imagetype.js",
            "src/js/volume/nifti/header-nifti.js", "src/js/volume/nifti/nifti.js",
            "src/js/volume/dicom/header-dicom.js", "src/js/volume/orientation.js", "src/js/volume/transform.js",
            "src/js/volume/volume.js", "src/js/volume/voxeldimensions.js", "src/js/volume/voxelvalue.js",
            "src/js/ui/dialog.js", "src/js/ui/menu.js", "src/js/ui/menuitem.js", "src/js/ui/menuitemcheckbox.js",
            "src/js/ui/menuitemfilechooser.js", "src/js/ui/menuitemrange.js", "src/js/ui/menuitemslider.js",
            "src/js/ui/menuitemspacer.js", "src/js/ui/toolbar.js", "src/js/viewer/atlas.js",
            "src/js/viewer/colortable.js", "src/js/viewer/display.js", "src/js/viewer/preferences.js",
            "src/js/viewer/screenslice.js", "src/js/viewer/screenvol.js", "src/js/viewer/viewer.js",
            "src/js/main.js", "src/js/license.js" };
    public static final String[] CSS_FILES = { "src/css/base.css", "src/css/ui/toolbar.css", "src/css/ui/menu.css",
            "src/css/ui/dialog.css", "src/css/utilities/nojs.css", "src/css/utilities/unsupported.css",
            "src/css/viewer/viewer.css" };
    public static final String RESOURCE_HTML = "index.html";
    public static final String SAMPLE_IMAGE_NII_FILE = "data/sample_image.nii.gz";
    public static final String SAMPLE_DEFAULT_ATLAS_FILE = "data/Talairach.xml";
    public static final String PAPAYA_LOADABLE_IMAGES = "papayaLoadableImages";
    public static final String DEFAULT_PARAMS = "var params = [];";

    public static void main(final String[] args) {
        final Builder builder = new Builder();

        // process command line
        final CommandLine cli = builder.createCLI(args);
        builder.setUseSample(cli.hasOption(ARG_SAMPLE));
        builder.setUseAtlas(cli.hasOption(ARG_ATLAS));
        builder.setLocal(cli.hasOption(ARG_LOCAL));
        builder.setPrintHelp(cli.hasOption(ARG_HELP));
        builder.setUseImages(cli.hasOption(ARG_IMAGE));
        builder.setSingleFile(cli.hasOption(ARG_SINGLE));
        builder.setUseParamFile(cli.hasOption(ARG_PARAM_FILE));
        builder.setUseTitle(cli.hasOption(ARG_TITLE));

        // print help, if necessary
        if (builder.isPrintHelp()) {
            builder.printHelp();
            return;
        }

        // find project root directory
        if (cli.hasOption(ARG_ROOT)) {
            try {
                builder.projectDir = (new File(cli.getOptionValue(ARG_ROOT))).getCanonicalFile();
            } catch (final IOException ex) {
                System.err.println("Problem finding root directory.  Reason: " + ex.getMessage());
            }
        }

        if (builder.projectDir == null) {
            builder.projectDir = new File(System.getProperty("user.dir"));
        }

        // clean output dir
        final File outputDir = new File(builder.projectDir + "/" + OUTPUT_DIR);
        System.out.println("Cleaning output directory...");
        try {
            builder.cleanOutputDir(outputDir);
        } catch (final IOException ex) {
            System.err.println("Problem cleaning build directory.  Reason: " + ex.getMessage());
        }

        if (builder.isLocal()) {
            System.out.println("Building for local usage...");
        }

        // write JS
        final File compressedFileJs = new File(outputDir, OUTPUT_JS_FILENAME);

        // build properties
        try {
            final File buildFile = new File(builder.projectDir + "/" + BUILD_PROP_FILE);

            builder.readBuildProperties(buildFile);
            builder.buildNumber++; // increment build number
            builder.writeBuildProperties(compressedFileJs, true);
            builder.writeBuildProperties(buildFile, false);
        } catch (final IOException ex) {
            System.err.println("Problem handling build properties.  Reason: " + ex.getMessage());
        }

        String htmlParameters = null;

        if (builder.isUseParamFile()) {
            final String paramFileArg = cli.getOptionValue(ARG_PARAM_FILE);

            if (paramFileArg != null) {
                try {
                    System.out.println("Including parameters...");

                    final String parameters = FileUtils.readFileToString(new File(paramFileArg), "UTF-8");
                    htmlParameters = "var params = " + parameters + ";";
                } catch (final IOException ex) {
                    System.err.println("Problem reading parameters file! " + ex.getMessage());
                }
            }
        }

        String title = null;
        if (builder.isUseTitle()) {
            String str = cli.getOptionValue(ARG_TITLE);
            if (str != null) {
                str = str.trim();
                str = str.replace("\"", "");
                str = str.replace("'", "");

                if (str.length() > 0) {
                    title = str;
                    System.out.println("Using title: " + title);
                }
            }
        }

        try {
            final JSONArray loadableImages = new JSONArray();

            // sample image
            if (builder.isUseSample()) {
                System.out.println("Including sample image...");

                final File sampleFile = new File(builder.projectDir + "/" + SAMPLE_IMAGE_NII_FILE);
                final String filename = Utilities
                        .replaceNonAlphanumericCharacters(Utilities.removeNiftiExtensions(sampleFile.getName()));

                if (builder.isLocal()) {
                    loadableImages.put(new JSONObject("{\"nicename\":\"Sample Image\",\"name\":\"" + filename
                            + "\",\"encode\":\"" + filename + "\"}"));
                    final String sampleEncoded = Utilities.encodeImageFile(sampleFile);
                    FileUtils.writeStringToFile(compressedFileJs,
                            "var " + filename + "= \"" + sampleEncoded + "\";\n", "UTF-8", true);
                } else {
                    loadableImages.put(new JSONObject("{\"nicename\":\"Sample Image\",\"name\":\"" + filename
                            + "\",\"url\":\"" + SAMPLE_IMAGE_NII_FILE + "\"}"));
                    FileUtils.copyFile(sampleFile, new File(outputDir + "/" + SAMPLE_IMAGE_NII_FILE));
                }
            }

            // atlas
            if (builder.isUseAtlas()) {
                Atlas atlas = null;

                try {
                    String atlasArg = cli.getOptionValue(ARG_ATLAS);

                    if (atlasArg == null) {
                        atlasArg = (builder.projectDir + "/" + SAMPLE_DEFAULT_ATLAS_FILE);
                    }

                    final File atlasXmlFile = new File(atlasArg);

                    System.out.println("Including atlas " + atlasXmlFile);

                    atlas = new Atlas(atlasXmlFile);
                    final File atlasJavaScriptFile = atlas.createAtlas(builder.isLocal());
                    System.out.println("Using atlas image file " + atlas.getImageFile());

                    if (builder.isLocal()) {
                        loadableImages.put(
                                new JSONObject("{\"nicename\":\"Atlas\",\"name\":\"" + atlas.getImageFileNewName()
                                        + "\",\"encode\":\"" + atlas.getImageFileNewName() + "\",\"hide\":true}"));
                    } else {
                        final File atlasImageFile = atlas.getImageFile();
                        final String atlasPath = "data/" + atlasImageFile.getName();

                        loadableImages.put(new JSONObject("{\"nicename\":\"Atlas\",\"name\":\""
                                + atlas.getImageFileNewName() + "\",\"url\":\"" + atlasPath + "\",\"hide\":true}"));
                        FileUtils.copyFile(atlasImageFile, new File(outputDir + "/" + atlasPath));
                    }

                    builder.writeFile(atlasJavaScriptFile, compressedFileJs);
                } catch (final IOException ex) {
                    System.err.println("Problem finding atlas file.  Reason: " + ex.getMessage());
                }
            }

            // additional images
            if (builder.isUseImages()) {
                final String[] imageArgs = cli.getOptionValues(ARG_IMAGE);

                if (imageArgs != null) {
                    for (final String imageArg : imageArgs) {
                        final File file = new File(imageArg);
                        System.out.println("Including image " + file);

                        final String filename = Utilities
                                .replaceNonAlphanumericCharacters(Utilities.removeNiftiExtensions(file.getName()));

                        if (builder.isLocal()) {
                            loadableImages.put(new JSONObject(
                                    "{\"nicename\":\"" + Utilities.removeNiftiExtensions(file.getName())
                                            + "\",\"name\":\"" + filename + "\",\"encode\":\"" + filename + "\"}"));
                            final String sampleEncoded = Utilities.encodeImageFile(file);
                            FileUtils.writeStringToFile(compressedFileJs,
                                    "var " + filename + "= \"" + sampleEncoded + "\";\n", "UTF-8", true);
                        } else {
                            final String filePath = "data/" + file.getName();
                            loadableImages.put(new JSONObject(
                                    "{\"nicename\":\"" + Utilities.removeNiftiExtensions(file.getName())
                                            + "\",\"name\":\"" + filename + "\",\"url\":\"" + filePath + "\"}"));
                            FileUtils.copyFile(file, new File(outputDir + "/" + filePath));
                        }
                    }
                }
            }

            File tempFileJs = null;

            try {
                tempFileJs = builder.createTempFile();
            } catch (final IOException ex) {
                System.err.println("Problem creating temp write file.  Reason: " + ex.getMessage());
            }

            // write image refs
            FileUtils.writeStringToFile(tempFileJs,
                    "var " + PAPAYA_LOADABLE_IMAGES + " = " + loadableImages.toString() + ";\n", "UTF-8", true);

            // compress JS
            tempFileJs = builder.concatenateFiles(JS_FILES, "js", tempFileJs);

            System.out.println("Compressing JavaScript... ");
            FileUtils.writeStringToFile(compressedFileJs, "\n", "UTF-8", true);
            builder.compressJavaScript(tempFileJs, compressedFileJs, new YuiCompressorOptions());
            //tempFileJs.deleteOnExit();
        } catch (final IOException ex) {
            System.err.println("Problem concatenating JavaScript.  Reason: " + ex.getMessage());
        }

        // compress CSS
        final File compressedFileCss = new File(outputDir, OUTPUT_CSS_FILENAME);

        try {
            final File concatFile = builder.concatenateFiles(CSS_FILES, "css", null);
            System.out.println("Compressing CSS... ");
            builder.compressCSS(concatFile, compressedFileCss, new YuiCompressorOptions());
            concatFile.deleteOnExit();
        } catch (final IOException ex) {
            System.err.println("Problem concatenating CSS.  Reason: " + ex.getMessage());
        }

        // write HTML
        try {
            System.out.println("Writing HTML... ");
            if (builder.singleFile) {
                builder.writeHtml(outputDir, compressedFileJs, compressedFileCss, htmlParameters, title);
            } else {
                builder.writeHtml(outputDir, htmlParameters, title);
            }
        } catch (final IOException ex) {
            System.err.println("Problem writing HTML.  Reason: " + ex.getMessage());
        }

        System.out.println("Done!  Output files located at " + outputDir);
    }

    @SuppressWarnings("static-access")
    private CommandLine createCLI(final String[] args) {
        this.options = new Options();
        this.options.addOption(new Option(ARG_SAMPLE, "include sample image"));
        this.options.addOption(new Option(ARG_LOCAL, "build for local usage"));
        this.options.addOption(new Option(ARG_SINGLE, "output a single HTML file"));
        this.options.addOption(new Option(ARG_HELP, "print this message"));
        this.options.addOption(OptionBuilder.withArgName("files").hasArgs().withDescription("images to include")
                .create(ARG_IMAGE));
        this.options.addOption(OptionBuilder.withArgName("dir").hasArg().withDescription("papaya project directory")
                .create(ARG_ROOT));
        this.options.addOption(
                OptionBuilder.withArgName("file").hasOptionalArg().withDescription("add atlas").create(ARG_ATLAS));
        this.options.addOption(OptionBuilder.withArgName("file").hasArg().withDescription("specify parameters")
                .create(ARG_PARAM_FILE));
        this.options.addOption(
                OptionBuilder.withArgName("text").hasArg().withDescription("add a title").create(ARG_TITLE));

        final CommandLineParser parser = new BasicParser();
        CommandLine line = null;

        try {
            line = parser.parse(this.options, args, true);
        } catch (final ParseException exp) {
            System.err.println("Parsing failed.  Reason: " + exp.getMessage());
        }

        return line;
    }

    private void cleanOutputDir(final File outputDir) throws IOException {
        Utilities.delete(outputDir);
        outputDir.mkdir();
    }

    private File concatenateFiles(final String[] files, final String ext, File writeFile) throws IOException {
        String concat = "";

        for (final String file2 : files) {
            final File file = new File(this.projectDir + "/" + file2);
            concat += FileUtils.readFileToString(file, "UTF-8") + "\n";
        }

        if (writeFile == null) {
            writeFile = createTempFile();
        }

        FileUtils.writeStringToFile(writeFile, concat, "UTF-8", true);

        return writeFile;
    }

    private File writeFile(final File readFile, File writeFile) throws IOException {
        if (writeFile == null) {
            writeFile = createTempFile();
        }

        final String str = FileUtils.readFileToString(readFile, "UTF-8");
        FileUtils.writeStringToFile(writeFile, str, "UTF-8", true);

        return writeFile;
    }

    private File createTempFile() throws IOException {
        return File.createTempFile(CLI_PROGRAM_NAME, null);
    }

    public void compressJavaScript(final File inputFile, final File outputFile, final YuiCompressorOptions o)
            throws IOException {
        Reader in = null;
        Writer out = null;
        try {
            in = new InputStreamReader(new FileInputStream(inputFile), o.charset);

            final JavaScriptCompressor compressor = new JavaScriptCompressor(in, new YuiCompressorErrorReporter());
            in.close();
            in = null;

            out = new OutputStreamWriter(new FileOutputStream(outputFile, true), o.charset);
            compressor.compress(out, o.lineBreakPos, o.munge, o.verbose, o.preserveAllSemiColons,
                    o.disableOptimizations);
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }

    public void compressCSS(final File inputFile, final File outputFile, final YuiCompressorOptions o)
            throws IOException {
        Reader in = null;
        Writer out = null;
        try {
            in = new InputStreamReader(new FileInputStream(inputFile), o.charset);

            final CssCompressor compressor = new CssCompressor(in);
            in.close();
            in = null;

            out = new OutputStreamWriter(new FileOutputStream(outputFile, true), o.charset);
            compressor.compress(out, o.lineBreakPos);
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }

    private void writeHtml(final File outputDir, final String params, final String title) throws IOException {
        final File resourceOutputFile = new File(outputDir, RESOURCE_HTML);

        String str = Utilities.getResourceAsString(RESOURCE_HTML);
        str = replaceHtmlParamsBlock(str, params);
        str = replaceHtmlTitleBlock(str, title);
        str = replaceHtmlPapayaBlock(str);
        str = replaceHtmlCssBlock(str, null);
        str = replaceHtmlJsBlock(str, null);

        FileUtils.writeStringToFile(resourceOutputFile, str, "UTF-8");
    }

    private void writeHtml(final File outputDir, final File jsFile, final File cssFile, final String params,
            final String title) throws IOException {
        final File resourceOutputFile = new File(outputDir, RESOURCE_HTML);

        String html = Utilities.getResourceAsString(RESOURCE_HTML);
        final String js = FileUtils.readFileToString(jsFile, "UTF-8");
        final String css = FileUtils.readFileToString(cssFile, "UTF-8");

        html = replaceHtmlParamsBlock(html, params);
        html = replaceHtmlTitleBlock(html, title);
        html = replaceHtmlPapayaBlock(html);
        html = replaceHtmlCssBlock(html, css);
        html = replaceHtmlJsBlock(html, js);

        FileUtils.writeStringToFile(resourceOutputFile, html, "UTF-8");

        jsFile.delete();
        jsFile.deleteOnExit();

        cssFile.delete();
        cssFile.deleteOnExit();
    }

    private String replaceHtmlCssBlock(final String html, final String cssBlock) {
        String css = null;

        if (cssBlock != null) {
            css = "<style type=\"text/css\">\n" + cssBlock + "\n</style>\n";
        } else {
            css = "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + "papaya.css?version=" + this.buildVersion
                    + "&build=" + this.buildNumber + "\" />";
        }

        return html.replace(CSS_BLOCK, css);
    }

    private String replaceHtmlJsBlock(final String html, final String jsBlock) {
        String js = null;

        if (jsBlock != null) {
            js = "<script type=\"text/javascript\">\n" + jsBlock + "\n</script>\n";
        } else {
            js = "<script type=\"text/javascript\" src=\"" + "papaya.js?version=" + this.buildVersion + "&build="
                    + this.buildNumber + "\"></script>";
        }

        return html.replace(JS_BLOCK, js);
    }

    private String replaceHtmlParamsBlock(final String html, final String params) {
        String js = null;

        if (params != null) {
            js = "<script type=\"text/javascript\">\n" + params + "\n</script>\n";
        } else {
            js = "<script type=\"text/javascript\">\n" + DEFAULT_PARAMS + "\n</script>\n";
        }

        return html.replace(PARAM_BLOCK, js);
    }

    private String replaceHtmlTitleBlock(final String html, final String titleStr) {
        String title = null;

        if (titleStr != null) {
            title = "<h3 style=\"text-align:center;font-family:sans-serif\">" + titleStr + "</h3>";
        } else {
            title = "";
        }

        return html.replace(TITLE_BLOCK, title);
    }

    private String replaceHtmlPapayaBlock(final String html) {
        String papaya = null;

        if (isUseTitle()) {
            papaya = "<div style=\"width:100%;text-align:center;\"><div class=\"papaya\" data-params=\"params\"></div></div>";
        } else {
            papaya = "<div class=\"papaya\" data-params=\"params\"></div>";
        }

        return html.replace(PAPAYA_BLOCK, papaya);
    }

    private void writeBuildProperties(final File file, final boolean append) throws IOException {
        FileUtils.writeStringToFile(file, BUILD_PROP_PAPAYA_VERSION_ID + "=\"" + this.buildVersion + "\";\n",
                "UTF-8", append);
        FileUtils.writeStringToFile(file, BUILD_PROP_PAPAYA_BUILD_NUM + "=\"" + this.buildNumber + "\";\n", "UTF-8",
                true);
    }

    private void printHelp() {
        final HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(CLI_PROGRAM_NAME + " [options]", this.options);
    }

    public boolean isLocal() {
        return this.isLocal;
    }

    public void setLocal(final boolean isLocal) {
        this.isLocal = isLocal;
    }

    public boolean isPrintHelp() {
        return this.printHelp;
    }

    public void setPrintHelp(final boolean printHelp) {
        this.printHelp = printHelp;
    }

    public boolean isUseSample() {
        return this.useSample;
    }

    public void setUseSample(final boolean useSample) {
        this.useSample = useSample;
    }

    public boolean isUseAtlas() {
        return this.useAtlas;
    }

    public void setUseAtlas(final boolean useAtlas) {
        this.useAtlas = useAtlas;
    }

    public boolean isUseImages() {
        return this.useImages;
    }

    public void setUseImages(final boolean useImages) {
        this.useImages = useImages;
    }

    // It's not a real Java properties file, so we need to handle reading it ourselves
    private void readBuildProperties(final File file) throws IOException {
        final List<String> lines = FileUtils.readLines(file);
        final Iterator<String> it = lines.iterator();

        while (it.hasNext()) {
            final String line = it.next();
            if (line.indexOf(BUILD_PROP_PAPAYA_VERSION_ID) != -1) {
                this.buildVersion = Utilities.findQuotedString(line);
            } else if (line.indexOf(BUILD_PROP_PAPAYA_BUILD_NUM) != -1) {
                this.buildNumber = Integer.parseInt(Utilities.findQuotedString(line));
            }
        }
    }

    public boolean isSingleFile() {
        return this.singleFile;
    }

    public void setSingleFile(final boolean singleFile) {
        this.singleFile = singleFile;
    }

    public boolean isUseParamFile() {
        return this.useParamFile;
    }

    public void setUseParamFile(final boolean useParamFile) {
        this.useParamFile = useParamFile;
    }

    public boolean isUseTitle() {
        return this.useTitle;
    }

    public void setUseTitle(final boolean useTitle) {
        this.useTitle = useTitle;
    }
}