org.cruxframework.crux.tools.compile.AbstractCruxCompiler.java Source code

Java tutorial

Introduction

Here is the source code for org.cruxframework.crux.tools.compile.AbstractCruxCompiler.java

Source

/*
 * Copyright 2011 cruxframework.org.
 * 
 * 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 org.cruxframework.crux.tools.compile;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cruxframework.crux.core.client.screen.InterfaceConfigException;
import org.cruxframework.crux.core.config.ConfigurationFactory;
import org.cruxframework.crux.core.declarativeui.ViewProcessor;
import org.cruxframework.crux.core.rebind.DevelopmentScanners;
import org.cruxframework.crux.core.rebind.module.Module;
import org.cruxframework.crux.core.rebind.screen.ScreenResourceResolverInitializer;
import org.cruxframework.crux.core.server.CruxBridge;
import org.cruxframework.crux.core.server.classpath.ClassPathResolverInitializer;
import org.cruxframework.crux.core.server.dispatch.ServiceFactoryInitializer;
import org.cruxframework.crux.core.server.rest.core.registry.RestServiceFactoryInitializer;
import org.cruxframework.crux.core.utils.FileUtils;
import org.cruxframework.crux.scanner.ClasspathUrlFinder;
import org.cruxframework.crux.scanner.Scanners;
import org.cruxframework.crux.tools.compile.utils.ClassPathUtils;
import org.cruxframework.crux.tools.compile.utils.ModuleUtils;
import org.cruxframework.crux.tools.parameters.ConsoleParameter;
import org.cruxframework.crux.tools.parameters.ConsoleParameterOption;
import org.cruxframework.crux.tools.parameters.ConsoleParametersProcessor;

import com.google.gwt.dev.Compiler;

/**
 * A Tool for crux projects compilation
 * @author Thiago da Rosa de Bustamante
 *
 */
public abstract class AbstractCruxCompiler {
    private static final Log logger = LogFactory.getLog(AbstractCruxCompiler.class);

    protected File compilerWorkDir;
    protected boolean indentPages;
    protected boolean initialized = false;
    protected boolean keepPagesGeneratedFiles;

    protected String outputCharset;
    protected File outputDir;

    protected String pageFileExtension;
    protected File pagesOutputDir;
    protected File webDir;

    private List<String> alreadyCompiledModules = new ArrayList<String>();
    private List<String> gwtCompilerArgs = new ArrayList<String>();
    private SecurityManager originalSecurityManager = null;
    private List<CruxPostProcessor> postProcessors = new ArrayList<CruxPostProcessor>();

    private boolean preCompileJavaSource = true;
    private List<CruxPreProcessor> preProcessors = new ArrayList<CruxPreProcessor>();

    protected File sourceDir;
    protected File resourcesDir;
    private File classpathDir;

    /**
     * @param parameters
     */
    public AbstractCruxCompiler() {
        CruxBridge.getInstance().setSingleVM(true);
        CruxRegisterUtil.removeOldTempFiles();
    }

    /**
     * Runs the crux compilation loop. 
     * 
     * <p>First, if a sourceFolder is provided, it is compiled.</p>
     * <p>Then, a scanner searches for modules, based on all crux pages found (returned by <code>getUrls()</code> method.).</p>
     * <p>Each of those modules is compiled and all pages found is pre processed and post processed.</p>
     * @throws CompilerException
     */
    public void execute() throws CompilerException {
        try {
            compileJavaSource();
            initializeCompiler();
            ServiceFactoryInitializer.initialize(null);
            RestServiceFactoryInitializer.initialize(null);
            for (Module module : getModules()) {
                boolean isModuleNotCompiled = !isModuleCompiled(module);
                if (isModuleNotCompiled) {
                    deleteModuleOutputDir(module);
                }

                Set<String> allScreenIDs = ScreenResourceResolverInitializer.getScreenResourceResolver()
                        .getAllScreenIDs(module.getName());
                for (String screenID : allScreenIDs) {
                    doCompileModule(new URL(screenID), module);
                }
            }
            releaseCompilerResources();
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw new CompilerException(e.getMessage(), e);
        }
    }

    public String getOutputCharset() {
        return outputCharset;
    }

    public File getOutputDir() {
        return outputDir;
    }

    public String getPageFileExtension() {
        return pageFileExtension;
    }

    public File getPagesOutputDir() {
        return pagesOutputDir;
    }

    public File getWebDir() {
        return webDir;
    }

    /**
     * 
     */
    public void initializeCompiler() {
        if (!initialized) {
            URL[] urls = ClasspathUrlFinder.findClassPaths();
            ModuleUtils.initializeScannerURLs(urls);
            Scanners.setSearchURLs(urls);
            DevelopmentScanners.initializeScanners();

            initializeProcessors();
            for (int i = 0; i < this.preProcessors.size(); i++) {
                this.preProcessors.get(i).initialize(urls);
            }
            for (int i = 0; i < this.postProcessors.size(); i++) {
                this.postProcessors.get(i).initialize(urls);
            }
            this.initialized = true;
        }
    }

    public boolean isIndentPages() {
        return indentPages;
    }

    public boolean isKeepPagesGeneratedFiles() {
        return keepPagesGeneratedFiles;
    }

    public boolean isPreCompileJavaSource() {
        return preCompileJavaSource;
    }

    public void setIndentPages(boolean indentPages) {
        this.indentPages = indentPages;
    }

    public void setKeepPagesGeneratedFiles(boolean keepPagesGeneratedFiles) {
        this.keepPagesGeneratedFiles = keepPagesGeneratedFiles;
    }

    public void setOutputCharset(String outputCharset) {
        ViewProcessor.setOutputCharset(outputCharset);
        this.outputCharset = outputCharset;
    }

    /**
     * @param parameter
     */
    public void setOutputDir(File file) {
        this.outputDir = file;
        this.gwtCompilerArgs.add("-war");
        try {
            this.gwtCompilerArgs.add(this.outputDir.getCanonicalPath());
        } catch (IOException e) {
            logger.error("Invalid output dir.", e);
        }
        if (this.webDir == null) {
            setWebDir(file);
        }
    }

    public void setPageFileExtension(String pageFileExtension) {
        this.pageFileExtension = pageFileExtension;
    }

    public void setPagesOutputDir(File pagesOutputDir) {
        this.pagesOutputDir = pagesOutputDir;
    }

    public void setPreCompileJavaSource(boolean preCompileJavaSource) {
        this.preCompileJavaSource = preCompileJavaSource;
    }

    /**
     * @param parameter
     */
    public void setScanAllowedPackages(String packages) {
        ConfigurationFactory.getConfigurations().setScanAllowedPackages(packages);
    }

    /**
     * @param parameter
     */
    public void setScanIgnoredPackages(String packages) {
        ConfigurationFactory.getConfigurations().setScanIgnoredPackages(packages);
    }

    /**
     * @param parameter
     */
    public void setWebDir(File file) {
        this.webDir = file;
        try {
            ClassPathResolverInitializer.getClassPathResolver()
                    .setWebInfClassesPath(new File(webDir, "WEB-INF/classes/").toURI().toURL());
            ClassPathResolverInitializer.getClassPathResolver()
                    .setWebInfLibPath(new File(webDir, "WEB-INF/lib/").toURI().toURL());
        } catch (MalformedURLException e) {
            logger.error("Invalid web folder");
        }
        if (this.outputDir == null) {
            setOutputDir(file);
        }
    }

    /**
     * @param postProcessor
     */
    protected void addPostProcessor(CruxPostProcessor postProcessor) {
        this.postProcessors.add(postProcessor);
    }

    /**
     * @param preProcessor
     */
    protected void addPreProcessor(CruxPreProcessor preProcessor) {
        this.preProcessors.add(preProcessor);
    }

    /**
     * Compile files using GWT compiler
     * @param url
     * @throws Exception
     */
    protected boolean compileFile(URL url, Module module) throws Exception {
        boolean compiled = false;

        if (module != null) {
            if (!isModuleCompiled(module)) {
                setModuleAsCompiled(module);
                doCompileFile(url, module.getFullName());
                compiled = true;
            }
        }

        return compiled;
    }

    /**
     * Pre compile java source folder, if provided
     */
    protected void compileJavaSource() throws CompilerException {
        if (preCompileJavaSource && sourceDir != null) {
            try {
                initializeCompilerDir();

                JCompiler compiler = new JCompiler();
                compiler.setOutputDirectory(compilerWorkDir);
                compiler.setSourcepath(sourceDir);
                if (classpathDir != null) {
                    compiler.setClasspath(getClasspath());
                }
                logger.info("Compiling java source");
                if (!compiler.compile(sourceDir)) {
                    throw new CompilerException("Error compiling java code. See console for details");
                }
            } catch (Exception e) {
                throw new CompilerException("Error initializing Java Compiler", e);
            }
        }
    }

    private String getClasspath() {
        //Wildcard is not supported by all JVM's, so let's use ';' approach.
        File[] listOfFiles = classpathDir.listFiles();
        StringBuffer classpath = new StringBuffer();
        for (int i = 0; i < listOfFiles.length; i++) {
            if (listOfFiles[i].isFile()) {
                classpath.append(listOfFiles[i].getAbsolutePath() + ";");
            }
        }
        return classpath.toString();
    }

    /**
     * @return
     */
    protected ConsoleParametersProcessor createParametersProcessor() {
        ConsoleParameter parameter;
        ConsoleParametersProcessor parametersProcessor = new ConsoleParametersProcessor(getProgramName());

        parameter = new ConsoleParameter("outputDir", "The folder where the compiled files will be created.", false,
                true);
        parameter.addParameterOption(new ConsoleParameterOption("dirName", "Folder name"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("sourceDir", "The project source folder.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("dirName", "Folder name"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("webDir", "The application web root folder.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("dirName", "Folder name"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("classpathDir", "The classpath folder.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("classpathDir", "Classpath dir"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("resourcesDir", "The resources folder.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("resourcesDir", "Resources dir"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("pagesOutputDir",
                "The folder where the generated page files will be created.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("output", "Folder name"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("scanAllowedPackages",
                "A list of packages (separated by commas) that will be scanned to find Controllers, Modules and CrossDevices",
                false, true);
        parameter.addParameterOption(new ConsoleParameterOption("allowed", "Allowed packages"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("scanIgnoredPackages",
                "A list of packages (separated by commas) that will not be scanned to find Controllers, Modules and CrossDevices",
                false, true);
        parameter.addParameterOption(new ConsoleParameterOption("ignored", "Ignored packages"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("outputCharset", "Charset used on output files", true, true);
        parameter.addParameterOption(new ConsoleParameterOption("charset", "Output charset"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("pageFileExtension", "Extension of the pages generated", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("fileExtension", "File Extension"));
        parametersProcessor.addSupportedParameter(parameter);

        parametersProcessor.addSupportedParameter(
                new ConsoleParameter("-indentPages", "If true, the output pages will be indented.", false, true));
        parametersProcessor.addSupportedParameter(new ConsoleParameter("-keepPagesGeneratedFiles",
                "If false, the output pages will be removed after compilation.", false, true));

        parametersProcessor.addSupportedParameter(new ConsoleParameter("-doNotPreCompileJavaSource",
                "Makes compiler ignore java pre compilation.", false, true));

        parameter = new ConsoleParameter("-gen",
                "Specify the folder where the GWT generators will output generated classes.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("genFolder", "Folder Name"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("-style", "Specify the output style for GWT generated code.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("style", "GWT output Style"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("-extra",
                "The directory into which extra files, not intended for deployment, will be written.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("extraFolder", "Folder Name"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("-localWorkers",
                "Number of threads used to compile the permutations in parallel.", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("numberOfWorkers", "Number of Workers"));
        parametersProcessor.addSupportedParameter(parameter);

        parameter = new ConsoleParameter("-logLevel", "Level of Logging", false, true);
        parameter.addParameterOption(new ConsoleParameterOption("level", "Level"));
        parametersProcessor.addSupportedParameter(parameter);

        parametersProcessor.addSupportedParameter(new ConsoleParameter("-validateOnly",
                " Validate all source code, but do not compile.", false, true));
        parametersProcessor.addSupportedParameter(new ConsoleParameter("-compileReport",
                "Create a compile report that tells the Story of Your Compile.", false, true));
        parametersProcessor.addSupportedParameter(new ConsoleParameter("-draftCompile",
                "Disable compiler optimizations and run faster.", false, true));
        parametersProcessor.addSupportedParameter(
                new ConsoleParameter("-strict", "Only succeed if no input files have errors.", false, true));
        parametersProcessor.addSupportedParameter(
                new ConsoleParameter("-XenableClosureCompiler", "Enable JS size optimizations.", false, true));
        parametersProcessor.addSupportedParameter(
                new ConsoleParameter("-XfragmentCount", "Enable automatic fragment merging.", false, false));
        parametersProcessor
                .addSupportedParameter(new ConsoleParameter("-help", "Display the usage screen.", false, true));
        parametersProcessor
                .addSupportedParameter(new ConsoleParameter("-h", "Display the usage screen.", false, true));
        return parametersProcessor;
    }

    /**
     * @param module
     */
    protected void deleteModuleOutputDir(Module module) {
        File output = new File(outputDir, module.getName());
        if (output.exists()) {
            FileUtils.recursiveDelete(output);
        }
        File backupFile = new File(FileUtils.getTempDirFile(), "_moduleBackup");
        if (backupFile.exists()) {
            FileUtils.recursiveDelete(backupFile);
        }
    }

    /**
     * @param url
     * @param moduleName
     */
    protected void doCompileFile(URL url, String moduleName) {
        logger.info("Compiling:" + url.toString());

        // Because of an AWT BUG, GWT needs to execute a System.exit command to 
        // finish its compilation. This class calls the Compiler from an ant command,
        // so, this bug is not a problem here. We need to compile all the modules on the same 
        // JVM. Call prerocessCruxPages on a separated JVM would cost a lot to our performance. 
        setSecurityManagerToAvoidSystemExit();

        try {
            Compiler.main(getGwtArgs(moduleName));
        } catch (DoNotExitException e) {
            //Do nothing...continue compile looping
        } finally {
            restoreSecurityManager();
        }
    }

    /**
     * @param url
     * @param module
     * @throws Exception
     */
    protected void doCompileModule(URL url, Module module) throws Exception {
        boolean isModuleNotCompiled = !isModuleCompiled(module);
        CruxBridge.getInstance().registerLastPageRequested(url.toString());
        URL preprocessedFile = preProcessCruxPage(url, module);
        if (isModuleNotCompiled) {
            maybeBackupPreProcessorsOutput(module);
            try {
                if (compileFile(preprocessedFile, module)) {
                    maybeRestoreBackup(module);
                }
            } catch (InterfaceConfigException e) {
                logger.error(e.getMessage());
            }
        } else {
            logger.info("Module '" + module.getFullName() + "' was already compiled. Skipping compilation.");
        }
        postProcessCruxPage(preprocessedFile, module);
    }

    /**
     * 
     * @param args
     */
    public void addGwtCompilerArgs(String[] args) {
        if (args != null) {
            for (String arg : args) {
                gwtCompilerArgs.add(arg);
            }
        }
    }

    /**
     * @param moduleName
     * @return
     */
    protected String[] getGwtArgs(String moduleName) {
        String[] gwtArgs = new String[gwtCompilerArgs.size() + 1];
        for (int i = 0; i < gwtCompilerArgs.size(); i++) {
            gwtArgs[i] = gwtCompilerArgs.get(i);
        }
        gwtArgs[gwtCompilerArgs.size()] = moduleName;
        return gwtArgs;
    }

    protected String getProgramName() {
        return "CruxCompiler";
    }

    /**
     * Gets the list of modules that will be compiled
     * @return
     */
    protected abstract List<Module> getModules() throws Exception;

    /**
     * @throws IOException
     * @throws MalformedURLException
     */
    protected void initializeCompilerDir() throws IOException, MalformedURLException {
        compilerWorkDir = new File(FileUtils.getTempDirFile(), "crux_compiler" + System.currentTimeMillis());
        compilerWorkDir.mkdirs();
        ClassPathUtils.addURL(compilerWorkDir.toURI().toURL());
        ClassPathResolverInitializer.getClassPathResolver().setWebInfClassesPath(compilerWorkDir.toURI().toURL());
    }

    protected abstract void initializeProcessors();

    /**
     * @param moduleName
     * @return
     */
    protected boolean isModuleCompiled(Module module) {
        return module != null && alreadyCompiledModules.contains(module.getFullName());
    }

    /**
     * @throws IOException 
     * 
     */
    protected void maybeBackupPreProcessorsOutput(Module module) throws IOException {
        File output = new File(outputDir, module.getName());
        if (output.exists()) {
            File backupFile = new File(FileUtils.getTempDirFile(), "_moduleBackup");
            FileUtils.copyDirectory(output, backupFile);
        }
    }

    /**
     * @param module
     * @throws IOException 
     */
    protected void maybeRestoreBackup(Module module) throws IOException {
        File backupFile = new File(FileUtils.getTempDirFile(), "_moduleBackup");
        if (backupFile.exists()) {
            File output = new File(outputDir, module.getName());
            FileUtils.copyDirectory(backupFile, output);
            backupFile.delete();
        }
    }

    /**
     * A chain composed by CruxPostProcessor object is used.
     * @param url
     * @param module
     * @return
     * @throws Exception 
     */
    protected void postProcessCruxPage(URL url, Module module) throws Exception {
        for (CruxPostProcessor postProcessor : this.postProcessors) {
            url = postProcessor.postProcess(url, module);
        }
        logger.info("File [" + url.toString() + "] post-processed.");
    }

    /**
     * A chain composed by CruxPreProcessor object is used.
     * @param url
     * @param module
     * @return
     * @throws Exception 
     */
    public URL preProcessCruxPage(URL url, Module module) throws Exception {
        for (CruxPreProcessor preprocess : this.preProcessors) {
            url = preprocess.preProcess(url, module);
        }
        logger.info("File [" + url.toString() + "] pre-processed.");

        return url;
    }

    /**
     * @param parameters
     */
    protected void processParameters(Collection<ConsoleParameter> parameters) {
        for (ConsoleParameter parameter : parameters) {
            String parameterName = parameter.getName();
            //GWT Parameters
            if (parameterName.equals("-gen") || parameterName.equals("-style") || parameterName.equals("-extra")
                    || parameterName.equals("-localWorkers") || parameterName.equals("-logLevel")
                    || parameterName.equals("-XfragmentCount")) {
                gwtCompilerArgs.add(parameterName);
                gwtCompilerArgs.add(parameter.getValue());
            } else if (parameterName.equals("-compileReport") || parameterName.equals("-strict")
                    || parameterName.equals("-draftCompile") || parameterName.equals("-validateOnly")
                    || parameterName.equals("-XenableClosureCompiler")) {
                gwtCompilerArgs.add(parameterName);
            }
            //Crux Parameters
            else if (parameterName.equals("outputDir")) {
                setOutputDir(new File(parameter.getValue()));
            } else if (parameterName.equals("webDir")) {
                setWebDir(new File(parameter.getValue()));
            } else if (parameterName.equals("scanAllowedPackages")) {
                setScanAllowedPackages(parameter.getValue());
            } else if (parameterName.equals("scanIgnoredPackages")) {
                setScanIgnoredPackages(parameter.getValue());
            } else if (parameterName.equals("pagesOutputDir")) {
                this.pagesOutputDir = new File(parameter.getValue());
            } else if (parameterName.equals("-indentPages")) {
                this.indentPages = true;
            } else if (parameterName.equals("-keepPagesGeneratedFiles")) {
                this.keepPagesGeneratedFiles = true;
            } else if (parameterName.equals("outputCharset")) {
                setOutputCharset(parameter.getValue());
            } else if (parameterName.equals("-doNotPreCompileJavaSource")) {
                this.preCompileJavaSource = false;
            } else if (parameterName.equals("pageFileExtension")) {
                this.pageFileExtension = parameter.getValue();
            }
        }
        if (this.outputDir == null && this.webDir == null) {
            logger.error("You must inform at least one of outputDir and webDir parameters.");
            System.exit(1);
        }
    }

    /**
     * @param parameters
     */
    protected void processSourceParameter(ConsoleParameter parameter) {
        if (parameter != null) {
            this.sourceDir = new File(parameter.getValue());
            try {
                ClassPathUtils.addURL(sourceDir.toURI().toURL());
            } catch (Exception e) {
                logger.error("Invalid sourceDir informed.", e);
                System.exit(1);
            }
        }
    }

    /**
     * @param parameters
     */
    public void processResourcesParameter(ConsoleParameter parameter) {
        if (parameter != null) {
            this.resourcesDir = new File(parameter.getValue());
            try {
                ClassPathUtils.addURL(resourcesDir.toURI().toURL());
            } catch (Exception e) {
                logger.error("Invalid resourcesDir informed.", e);
                System.exit(1);
            }
        }
    }

    /**
     * @param parameters
     */
    protected void processClasspathParameter(ConsoleParameter parameter) {
        if (parameter != null) {
            try {
                this.classpathDir = new File(parameter.getValue());
                String[] classpaths = getClasspath().split(";");
                for (String classpath : classpaths) {
                    ClassPathUtils.addURL(new File(classpath).toURI().toURL());
                }
            } catch (Exception e) {
                logger.error("Invalid classpathDir informed.", e);
                System.exit(1);
            }
        }
    }

    /**
     * Release any resource reserved during compilation
     */
    protected void releaseCompilerResources() {
        if (compilerWorkDir != null && compilerWorkDir.exists()) {
            FileUtils.recursiveDelete(compilerWorkDir);
        }
    }

    /**
     * @param module
     */
    protected void setModuleAsCompiled(Module module) {
        if (module != null) {
            alreadyCompiledModules.add(module.getFullName());
        }
    }

    /**
     * 
     */
    private void restoreSecurityManager() {
        AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
            public Boolean run() {
                System.setSecurityManager(originalSecurityManager);
                return true;
            }
        });
    }

    /**
     * 
     */
    private void setSecurityManagerToAvoidSystemExit() {
        AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
            public Boolean run() {
                originalSecurityManager = System.getSecurityManager();
                System.setSecurityManager(new SecurityManager() {

                    @Override
                    public void checkExit(int status) {
                        if (status == 0) {
                            throw new DoNotExitException();
                        }
                        super.checkExit(status);
                    }

                    @Override
                    public void checkPermission(Permission perm) {
                    }

                    @Override
                    public void checkPermission(Permission perm, Object context) {
                    }
                });
                return true;
            }
        });
    }

    /**
     * @author Thiago da Rosa de Bustamante
     *
     */
    private static class DoNotExitException extends SecurityException {
        private static final long serialVersionUID = -5285052847615664828L;
    }
}