com.xqbase.compiler.eclipse.EclipseJavaCompiler.java Source code

Java tutorial

Introduction

Here is the source code for com.xqbase.compiler.eclipse.EclipseJavaCompiler.java

Source

// package org.codehaus.plexus.compiler.eclipse;
package com.xqbase.compiler.eclipse;

/**
 * The MIT License
 *
 * Copyright (c) 2005, The Codehaus
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

import org.codehaus.plexus.compiler.AbstractCompiler;
import org.codehaus.plexus.compiler.CompilerConfiguration;
import org.codehaus.plexus.compiler.CompilerException;
import org.codehaus.plexus.compiler.CompilerMessage;
import org.codehaus.plexus.compiler.CompilerOutputStyle;
import org.codehaus.plexus.compiler.CompilerResult;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

/*
 * @plexus.component role="org.codehaus.plexus.compiler.Compiler" role-hint="eclipse"
 */
public class EclipseJavaCompiler extends AbstractCompiler {
    public EclipseJavaCompiler() {
        super(CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, ".java", ".class", null);
    }

    // ----------------------------------------------------------------------
    // Compiler Implementation
    // ----------------------------------------------------------------------

    public CompilerResult performCompile(CompilerConfiguration config) throws CompilerException {

        // added by xqbase-compiler-eclipse
        if (config.getGeneratedSourcesDirectory() != null) {
            config.getGeneratedSourcesDirectory().mkdirs();
        }

        List<CompilerMessage> errors = new LinkedList<CompilerMessage>();

        List<String> classpathEntries = config.getClasspathEntries();

        URL[] urls = new URL[1 + classpathEntries.size()];

        int i = 0;

        try {
            urls[i++] = new File(config.getOutputLocation()).toURL();

            for (String entry : classpathEntries) {
                urls[i++] = new File(entry).toURL();
            }
        } catch (MalformedURLException e) {
            throw new CompilerException("Error while converting the classpath entries to URLs.", e);
        }

        ClassLoader classLoader = new URLClassLoader(urls);

        SourceCodeLocator sourceCodeLocator = new SourceCodeLocator(config.getSourceLocations());

        INameEnvironment env = new EclipseCompilerINameEnvironment(sourceCodeLocator, classLoader, errors);

        IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.proceedWithAllProblems();

        // ----------------------------------------------------------------------
        // Build settings from configuration
        // ----------------------------------------------------------------------

        Map<String, String> settings = new HashMap<String, String>();

        if (config.isDebug()) {
            settings.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE);
            settings.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE);
            settings.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE);
        }

        if (!config.isShowWarnings()) {
            Map opts = new CompilerOptions().getMap();
            for (Object optKey : opts.keySet()) {
                if (opts.get(optKey).equals(CompilerOptions.WARNING)) {
                    settings.put((String) optKey, CompilerOptions.IGNORE);
                }
            }
        }

        String sourceVersion = decodeVersion(config.getSourceVersion());

        if (sourceVersion != null) {
            settings.put(CompilerOptions.OPTION_Source, sourceVersion);
        }

        String targetVersion = decodeVersion(config.getTargetVersion());

        if (targetVersion != null) {
            settings.put(CompilerOptions.OPTION_TargetPlatform, targetVersion);

            if (config.isOptimize()) {
                settings.put(CompilerOptions.OPTION_Compliance, targetVersion);
            }
        }

        if (StringUtils.isNotEmpty(config.getSourceEncoding())) {
            settings.put(CompilerOptions.OPTION_Encoding, config.getSourceEncoding());
        }

        if (config.isShowDeprecation()) {
            settings.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
        } else {
            settings.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE);
        }

        // ----------------------------------------------------------------------
        // Set Eclipse-specific options
        // ----------------------------------------------------------------------

        settings.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE);
        settings.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE);

        // compiler-specific extra options override anything else in the config object...
        Map<String, String> extras = config.getCustomCompilerArguments();
        if (extras != null && !extras.isEmpty()) {
            settings.putAll(extras);
        }

        if (settings.containsKey("-properties")) {
            initializeWarnings(settings.get("-properties"), settings);
            settings.remove("-properties");
        }

        IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());

        ICompilerRequestor requestor = new EclipseCompilerICompilerRequestor(config.getOutputLocation(), errors);

        List<CompilationUnit> compilationUnits = new ArrayList<CompilationUnit>();

        for (String sourceRoot : config.getSourceLocations()) {
            Set<String> sources = getSourceFilesForSourceRoot(config, sourceRoot);

            for (String source : sources) {
                CompilationUnit unit = new CompilationUnit(source, makeClassName(source, sourceRoot), errors,
                        config.getSourceEncoding());

                compilationUnits.add(unit);
            }
        }

        // ----------------------------------------------------------------------
        // Compile!
        // ----------------------------------------------------------------------

        CompilerOptions options = new CompilerOptions(settings);
        Compiler compiler = new Compiler(env, policy, options, requestor, problemFactory);

        ICompilationUnit[] units = compilationUnits.toArray(new ICompilationUnit[compilationUnits.size()]);

        compiler.compile(units);

        CompilerResult compilerResult = new CompilerResult().compilerMessages(errors);

        for (CompilerMessage compilerMessage : errors) {
            if (compilerMessage.isError()) {
                compilerResult.setSuccess(false);
                continue;
            }
        }

        return compilerResult;
    }

    public String[] createCommandLine(CompilerConfiguration config) throws CompilerException {
        return null;
    }

    private CompilerMessage handleError(String className, int line, int column, Object errorMessage) {
        if (className.endsWith(".java")) {
            className = className.substring(0, className.lastIndexOf('.'));
        }
        String fileName = className.replace('.', File.separatorChar) + ".java";

        if (column < 0) {
            column = 0;
        }

        String message;

        if (errorMessage != null) {
            message = errorMessage.toString();
        } else {
            message = "No message";
        }

        return new CompilerMessage(fileName, CompilerMessage.Kind.ERROR, line, column, line, column, message);

    }

    private CompilerMessage handleWarning(String fileName, IProblem warning) {
        return new CompilerMessage(fileName, CompilerMessage.Kind.WARNING, warning.getSourceLineNumber(),
                warning.getSourceStart(), warning.getSourceLineNumber(), warning.getSourceEnd(),
                warning.getMessage());
    }

    private String decodeVersion(String versionSpec) {
        if (StringUtils.isEmpty(versionSpec)) {
            return null;
        } else if ("1.1".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_1;
        } else if ("1.2".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_2;
        } else if ("1.3".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_3;
        } else if ("1.4".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_4;
        } else if ("1.5".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_5;
        } else if ("1.6".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_6;
        } else if ("1.7".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_7;
        }
        // added by xqbase-compiler-eclipse
        else if ("1.8".equals(versionSpec)) {
            return CompilerOptions.VERSION_1_8;
        } else {
            getLogger().warn(
                    "Unknown version '" + versionSpec + "', no version setting will be given to the compiler.");

            return null;
        }
    }

    // ----------------------------------------------------------------------
    // Classes
    // ----------------------------------------------------------------------

    private class CompilationUnit implements ICompilationUnit {
        private final String className;

        private final String sourceFile;

        private final String sourceEncoding;

        private final List<CompilerMessage> errors;

        CompilationUnit(String sourceFile, String className, List<CompilerMessage> errors) {
            this(sourceFile, className, errors, null);
        }

        CompilationUnit(String sourceFile, String className, List<CompilerMessage> errors, String sourceEncoding) {
            this.className = className;
            this.sourceFile = sourceFile;
            this.errors = errors;
            this.sourceEncoding = sourceEncoding;
        }

        public char[] getFileName() {
            String fileName = sourceFile;

            int lastSeparator = fileName.lastIndexOf(File.separatorChar);

            if (lastSeparator > 0) {
                fileName = fileName.substring(lastSeparator + 1);
            }

            return fileName.toCharArray();
        }

        String getAbsolutePath() {
            return sourceFile;
        }

        public char[] getContents() {
            try {
                return FileUtils.fileRead(sourceFile, sourceEncoding).toCharArray();
            } catch (FileNotFoundException e) {
                errors.add(handleError(className, -1, -1, e.getMessage()));

                return null;
            } catch (IOException e) {
                errors.add(handleError(className, -1, -1, e.getMessage()));

                return null;
            }
        }

        public char[] getMainTypeName() {
            int dot = className.lastIndexOf('.');

            if (dot > 0) {
                return className.substring(dot + 1).toCharArray();
            }

            return className.toCharArray();
        }

        public char[][] getPackageName() {
            StringTokenizer izer = new StringTokenizer(className, ".");

            char[][] result = new char[izer.countTokens() - 1][];

            for (int i = 0; i < result.length; i++) {
                String tok = izer.nextToken();

                result[i] = tok.toCharArray();
            }

            return result;
        }

        public boolean ignoreOptionalProblems() {
            return false;
        }
    }

    private class EclipseCompilerINameEnvironment implements INameEnvironment {
        private SourceCodeLocator sourceCodeLocator;

        private ClassLoader classLoader;

        private List<CompilerMessage> errors;

        public EclipseCompilerINameEnvironment(SourceCodeLocator sourceCodeLocator, ClassLoader classLoader,
                List<CompilerMessage> errors) {
            this.sourceCodeLocator = sourceCodeLocator;
            this.classLoader = classLoader;
            this.errors = errors;
        }

        public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
            String result = "";

            String sep = "";

            for (int i = 0; i < compoundTypeName.length; i++) {
                result += sep;
                result += new String(compoundTypeName[i]);
                sep = ".";
            }

            return findType(result);
        }

        public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
            String result = "";

            String sep = "";

            for (int i = 0; i < packageName.length; i++) {
                result += sep;
                result += new String(packageName[i]);
                sep = ".";
            }

            result += sep;
            result += new String(typeName);
            return findType(result);
        }

        private NameEnvironmentAnswer findType(String className) {
            try {
                File f = sourceCodeLocator.findSourceCodeForClass(className);

                if (f != null) {
                    ICompilationUnit compilationUnit = new CompilationUnit(f.getAbsolutePath(), className, errors);

                    return new NameEnvironmentAnswer(compilationUnit, null);
                }

                String resourceName = className.replace('.', '/') + ".class";

                InputStream is = classLoader.getResourceAsStream(resourceName);

                if (is == null) {
                    return null;
                }

                byte[] classBytes = IOUtil.toByteArray(is);

                char[] fileName = className.toCharArray();

                ClassFileReader classFileReader = new ClassFileReader(classBytes, fileName, true);

                return new NameEnvironmentAnswer(classFileReader, null);
            } catch (IOException e) {
                errors.add(handleError(className, -1, -1, e.getMessage()));

                return null;
            } catch (ClassFormatException e) {
                errors.add(handleError(className, -1, -1, e.getMessage()));

                return null;
            }
        }

        private boolean isPackage(String result) {
            if (sourceCodeLocator.findSourceCodeForClass(result) != null) {
                return false;
            }

            String resourceName = "/" + result.replace('.', '/') + ".class";

            InputStream is = classLoader.getResourceAsStream(resourceName);

            return is == null;
        }

        public boolean isPackage(char[][] parentPackageName, char[] packageName) {
            String result = "";

            String sep = "";

            if (parentPackageName != null) {
                for (int i = 0; i < parentPackageName.length; i++) {
                    result += sep;
                    result += new String(parentPackageName[i]);
                    sep = ".";
                }
            }

            if (Character.isUpperCase(packageName[0])) {
                return false;
            }

            String str = new String(packageName);

            result += sep;

            result += str;

            return isPackage(result);
        }

        public void cleanup() {
            // nothing to do
        }
    }

    private class EclipseCompilerICompilerRequestor implements ICompilerRequestor {
        private String destinationDirectory;

        private List<CompilerMessage> errors;

        public EclipseCompilerICompilerRequestor(String destinationDirectory, List<CompilerMessage> errors) {
            this.destinationDirectory = destinationDirectory;
            this.errors = errors;
        }

        public void acceptResult(CompilationResult result) {
            boolean hasErrors = false;

            if (result.hasProblems()) {
                IProblem[] problems = result.getProblems();

                for (IProblem problem : problems) {
                    String name = getFileName(result.getCompilationUnit(), problem.getOriginatingFileName());

                    if (problem.isWarning()) {
                        errors.add(handleWarning(name, problem));
                    } else {
                        hasErrors = true;
                        errors.add(handleError(name, problem.getSourceLineNumber(), -1, problem.getMessage()));
                    }
                }
            }

            if (!hasErrors) {
                ClassFile[] classFiles = result.getClassFiles();

                for (ClassFile classFile : classFiles) {
                    char[][] compoundName = classFile.getCompoundName();
                    String className = "";
                    String sep = "";

                    for (int j = 0; j < compoundName.length; j++) {
                        className += sep;
                        className += new String(compoundName[j]);
                        sep = ".";
                    }

                    byte[] bytes = classFile.getBytes();

                    File outFile = new File(destinationDirectory, className.replace('.', '/') + ".class");

                    if (!outFile.getParentFile().exists()) {
                        outFile.getParentFile().mkdirs();
                    }

                    FileOutputStream fout = null;

                    try {
                        fout = new FileOutputStream(outFile);

                        fout.write(bytes);
                    } catch (FileNotFoundException e) {
                        errors.add(handleError(className, -1, -1, e.getMessage()));
                    } catch (IOException e) {
                        errors.add(handleError(className, -1, -1, e.getMessage()));
                    } finally {
                        IOUtil.close(fout);
                    }
                }
            }
        }

        private String getFileName(ICompilationUnit compilationUnit, char[] originalFileName) {
            if (compilationUnit instanceof CompilationUnit) {
                return ((CompilationUnit) compilationUnit).getAbsolutePath();
            } else {
                return String.valueOf(originalFileName);
            }
        }
    }

    private void initializeWarnings(String propertiesFile, Map<String, String> setting) {
        File file = new File(propertiesFile);
        if (!file.exists()) {
            throw new IllegalArgumentException("Properties file not exist");
        }
        BufferedInputStream stream = null;
        Properties properties = null;
        try {
            stream = new BufferedInputStream(new FileInputStream(propertiesFile));
            properties = new Properties();
            properties.load(stream);
        } catch (IOException e) {
            throw new IllegalArgumentException("Properties file load error");
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
        for (Iterator iterator = properties.entrySet().iterator(); iterator.hasNext();) {
            Map.Entry entry = (Map.Entry) iterator.next();
            final String key = (String) entry.getKey();
            setting.put(key, entry.getValue().toString());
        }
    }
}