View Javadoc
1   /*
2    * Copyright 2006 Ralf Jaochim
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  package org.castor.xmlctf.compiler;
15  
16  import java.io.File;
17  import java.io.IOException;
18  import java.io.StringWriter;
19  import java.io.Writer;
20  import java.lang.reflect.Method;
21  import java.util.ArrayList;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Set;
25  
26  import javax.tools.JavaCompiler;
27  import javax.tools.JavaFileObject;
28  import javax.tools.StandardJavaFileManager;
29  import javax.tools.ToolProvider;
30  
31  import org.castor.xmlctf.XMLTestCase;
32  import org.castor.xmlctf.util.FileServices;
33  
34  /**
35   * Compiles a directory tree, recursively. This class is built to use the Oracle tool JavaCompiler
36   * contained in tools.jar. A IllegalStateException will be thrown if tools.jar is not on the
37   * classpath at construction of the class and execution of the compileDirectory() method.
38   *
39   * @version $Revision: 5951 $ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $
40   * @since 1.3.4
41   */
42  public class OracleJavaCompiler implements Compiler {
43  
44    private static final Set<String> IGNORE_DIRS = new HashSet<String>();
45  
46    /** Java version of the JVM we are running in. */
47    private static final float JAVA_VERSION =
48        Float.parseFloat(System.getProperty("java.specification.version"));
49  
50    private String _javaVersion = null;
51  
52    private final File _baseDirectory;
53    private final File _outputDirectory;
54  
55    static {
56      IGNORE_DIRS.add(FileServices.CVS);
57      IGNORE_DIRS.add(FileServices.SVN);
58      IGNORE_DIRS.add(FileServices.GIT);
59    }
60  
61    /**
62     * Creates a compiler for a given directory.
63     * 
64     * @param baseDirectory The directory that holds the files to be compiled.
65     */
66    public OracleJavaCompiler(File baseDirectory) {
67      if (baseDirectory == null) {
68        throw new IllegalArgumentException("'baseDirectory' must not be null.");
69      }
70      _baseDirectory = baseDirectory;
71      _outputDirectory = baseDirectory;
72    }
73  
74    /**
75     * Sets the Java source version the current test will be using.
76     * 
77     * @param javaSourceVersion The Java Source version to be used.
78     */
79    public void setJavaSourceVersion(float javaSourceVersion) {
80      float srcVersion = javaSourceVersion;
81      if (javaSourceVersion >= 5F && javaSourceVersion < 10F) {
82        srcVersion = 1.0F + (javaSourceVersion / 10F);
83      }
84      _javaVersion = "" + srcVersion;
85    }
86  
87    /**
88     * Compiles the content of a directory. Throws a <code>CompilationException</code> if the build
89     * fails.
90     */
91    public void compileDirectory() {
92      List<File> filesList = findSourceFiles(_baseDirectory);
93      if (!filesList.isEmpty()) {
94        // filesList.addAll(0, getCompileArguments(_baseDirectory,
95        // _outputDirectory));
96  
97        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
98        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
99        // TODO: file list - do not convert to Strings
100       Iterable<? extends JavaFileObject> compilationUnits =
101           fileManager.getJavaFileObjectsFromFiles(filesList);
102       Iterable<String> compileOptions = getCompileArguments(_baseDirectory, _outputDirectory);
103       // Iterable<String> compileOptions = Arrays.asList("-g", "-d",
104       // "-cp", CLASSPATH);
105       Writer logger = new StringWriter();
106       JavaCompiler.CompilationTask task =
107           compiler.getTask(logger, fileManager, null, compileOptions, null, compilationUnits);
108       boolean ok = task.call();
109       try {
110         fileManager.close();
111       } catch (IOException ioe) {
112         // TODO
113         ioe.printStackTrace(System.err);
114       }
115 
116       System.out.println(logger.toString());
117 
118       if (ok == false) {
119         throw new IllegalStateException("Failed to call compile method.");
120       }
121 
122     } else {
123       throw new CompilationException("No files to compile: " + _baseDirectory);
124     }
125   }
126 
127   /**
128    * Returns a list of arguments for the compiler.
129    * 
130    * @param srcDir The source directory for compilation
131    * @param destDir The destination directory for compilation
132    * @return a list of arguments for the compiler.
133    */
134   private List<String> getCompileArguments(final File srcDir, final File destDir) {
135     List<String> args = new ArrayList<String>();
136 
137     args.add("-g");
138     if (JAVA_VERSION == 1.5F || JAVA_VERSION == 1.6F || JAVA_VERSION == 1.7F) {
139       args.add("-Xlint:unchecked");
140     }
141     if (XMLTestCase._verbose) {
142       args.add("-verbose");
143     } else {
144       args.add("-nowarn");
145       args.add("-Xmaxwarns");
146       args.add("0");
147       args.add("-Xmaxerrs");
148       args.add("5");
149     }
150     if (_javaVersion != null) {
151       args.add("-source");
152       args.add(_javaVersion);
153     }
154     args.add("-classpath");
155     String classPathOverriden = System.getProperty("xmlctf.classpath.override");
156     if (classPathOverriden != null) {
157       args.add(classPathOverriden + ";" + destDir.getAbsolutePath());
158     } else {
159       args.add(System.getProperty("java.class.path") + ";" + destDir.getAbsolutePath());
160     }
161     args.add("-d");
162     args.add(destDir.getAbsolutePath());
163     args.add("-sourcepath");
164     args.add(srcDir.getAbsolutePath());
165     args.add("-g");
166     return args;
167   }
168 
169   /**
170    * Recursively searches the provided directory, returning a list of all Java files found.
171    * 
172    * @param sourceDirectory A directory to search for Java files.
173    * @return a List of all Java files found in the provided directory
174    */
175   private List<File> findSourceFiles(File sourceDirectory) {
176     List<File> files = new ArrayList<File>();
177 
178     File[] entries = sourceDirectory.listFiles();
179     for (int i = 0; i < entries.length; i++) {
180       File entry = entries[i];
181       if (entry.getName().endsWith(".java")) {
182         files.add(entry);
183       } else if (entry.isDirectory() && !IGNORE_DIRS.contains(entry.getName())) {
184         files.addAll(findSourceFiles(entry));
185       }
186     }
187 
188     return files;
189   }
190 
191 }