All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.qwazr.compiler.JavaCompiler Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
/**
 * Copyright 2015-2017 Emmanuel Keller / QWAZR
 * 

* 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 com.qwazr.compiler; import com.qwazr.classloader.ClassLoaderManager; import com.qwazr.server.ServerException; import com.qwazr.utils.LockUtils; import com.qwazr.utils.StringUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.io.filefilter.FileFileFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; public class JavaCompiler { private final static Logger LOGGER = LoggerFactory.getLogger(JavaCompiler.class); private final ClassLoaderManager classLoaderManager; private final int javaSourcePrefixSize; private final File javaSourceDirectory; private final File javaClassesDirectory; private final LinkedHashSet classPathSet; private final String compiledClassPath; private final LockUtils.ReadWriteLock compilerLock; private final ConcurrentHashMap compilableMap; private final ConcurrentHashMap diagnosticMap; private JavaCompiler(final ClassLoaderManager classLoaderManager, final File javaSourceDirectory, final File javaClassesDirectory, final LinkedHashSet classPathSet) throws IOException { this.classLoaderManager = classLoaderManager; this.classPathSet = classPathSet; this.compiledClassPath = classPathSet != null && !classPathSet.isEmpty() ? StringUtils.join(classPathSet, File.pathSeparatorChar) : null; this.compilableMap = new ConcurrentHashMap<>(); this.diagnosticMap = new ConcurrentHashMap<>(); this.javaSourceDirectory = javaSourceDirectory; String javaSourcePrefix = javaSourceDirectory.getAbsolutePath(); javaSourcePrefixSize = javaSourcePrefix.endsWith("/") ? javaSourcePrefix.length() : javaSourcePrefix.length() + 1; this.javaClassesDirectory = javaClassesDirectory; if (this.javaClassesDirectory != null && !this.javaClassesDirectory.exists()) this.javaClassesDirectory.mkdir(); compilerLock = new LockUtils.ReadWriteLock(); if (javaSourceDirectory.exists() && javaSourceDirectory.isDirectory()) compileDirectory(javaSourceDirectory); else LOGGER.warn("No java source directory: " + javaSourceDirectory.getAbsolutePath()); } static JavaCompiler newInstance(final ClassLoaderManager classLoaderManager, final File javaSourceDirectory, final File javaClassesDirectory, final File... classPathDirectories) throws IOException, URISyntaxException { Objects.requireNonNull(javaSourceDirectory, "No source directory given (null)"); Objects.requireNonNull(javaClassesDirectory, "No class directory given (null)"); final LinkedHashSet urlList = new LinkedHashSet<>(); urlList.add(javaClassesDirectory.toURI().toURL()); final LinkedHashSet classPath = buildClassPath(classPathDirectories, urlList); return new JavaCompiler(classLoaderManager, javaSourceDirectory, javaClassesDirectory, classPath); } private static LinkedHashSet buildClassPath(final File[] classPathArray, final Collection urlCollection) throws MalformedURLException, URISyntaxException { final LinkedHashSet classPathes = new LinkedHashSet<>(); final String classPath = System.getProperty("java.class.path"); if (!StringUtils.isEmpty(classPath)) classPathes.addAll(Arrays.asList(StringUtils.split(classPath, File.pathSeparatorChar))); if (classPathArray != null) { for (File classPathFile : classPathArray) { if (classPathFile.isDirectory()) { File[] classPathFiles = classPathFile.listFiles((FileFilter) FileFileFilter.FILE); if (classPathFiles != null) { for (File f : classPathFiles) { classPathes.add(f.getAbsolutePath()); urlCollection.add(f.toURI().toURL()); } } } else if (classPathFile.isFile()) { classPathes.add(classPathFile.getAbsolutePath()); urlCollection.add(classPathFile.toURI().toURL()); } } } return classPathes; } private boolean compile(final javax.tools.JavaCompiler compiler, final Collection javaFiles, final AtomicInteger counter) throws IOException { final DiagnosticCollector diagnostics = new DiagnosticCollector<>(); try (final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) { final Iterable sourceFileObjects = fileManager.getJavaFileObjectsFromFiles(javaFiles); final List options = new ArrayList<>(); if (compiledClassPath != null && !compiledClassPath.isEmpty()) { options.add("-classpath"); options.add(compiledClassPath); } options.add("-d"); options.add(javaClassesDirectory.getAbsolutePath()); options.add("-sourcepath"); options.add(javaSourceDirectory.getAbsolutePath()); javax.tools.JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, sourceFileObjects); final Date date = new Date(); final boolean compilationSuccess = task.call(); for (File file : javaFiles) { final URI fileUri = file.toURI(); compilableMap.put(fileUri, date); diagnosticMap.remove(fileUri); } counter.addAndGet(javaFiles.size()); for (final Diagnostic diagnostic : diagnostics.getDiagnostics()) { if (diagnostic == null) continue; final JavaFileObject source = diagnostic.getSource(); if (source == null) continue; final URI uri = source.toUri(); if (uri != null) diagnosticMap.put(uri, new CompilerStatus.DiagnosticStatus(date, diagnostic)); if (LOGGER.isWarnEnabled()) LOGGER.warn( String.format("Error on line %d in %s%n%s", diagnostic.getLineNumber(), source.getName(), diagnostic.getMessage(null))); } return compilationSuccess; } } private Collection filterUptodate(final File parentDir, final File[] javaSourceFiles) { if (javaSourceFiles == null) return null; final Collection finalJavaFiles = new ArrayList<>(); if (javaSourceFiles.length == 0) return finalJavaFiles; final File parentClassDir = new File(javaClassesDirectory, parentDir.getAbsolutePath().substring(javaSourcePrefixSize)); for (File javaSourceFile : javaSourceFiles) { final File classFile = new File(parentClassDir, FilenameUtils.removeExtension(javaSourceFile.getName()) + ".class"); if (classFile.exists() && classFile.lastModified() > javaSourceFile.lastModified()) { compilableMap.put(javaSourceFile.toURI(), new Date(classFile.lastModified())); continue; } finalJavaFiles.add(javaSourceFile); } return finalJavaFiles; } private void compileDirectory(final javax.tools.JavaCompiler compiler, final File sourceDirectory, final AtomicInteger counter) { final Collection javaFiles = filterUptodate(sourceDirectory, sourceDirectory.listFiles(javaFileFilter)); if (javaFiles != null && javaFiles.size() > 0) { if (LOGGER.isInfoEnabled()) LOGGER.info("Compile " + javaFiles.size() + " JAVA file(s) at " + sourceDirectory); try { compile(compiler, javaFiles, counter); } catch (IOException e) { throw new ServerException(e); } } final File[] dirFiles = sourceDirectory.listFiles((FileFilter) DirectoryFileFilter.INSTANCE); if (dirFiles != null) for (File dir : dirFiles) compileDirectory(compiler, dir, counter); } private void compileDirectory(File sourceDirectory) throws IOException { if (sourceDirectory == null) return; if (!sourceDirectory.isDirectory()) return; compilerLock.writeEx(() -> { javax.tools.JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); Objects.requireNonNull(compiler, "No compiler is available. This feature requires a JDK (not a JRE)."); final AtomicInteger counter = new AtomicInteger(); compileDirectory(compiler, sourceDirectory, counter); if (counter.get() > 0) classLoaderManager.reload(); }); } private final JavaFileFilter javaFileFilter = new JavaFileFilter(); private class JavaFileFilter implements FileFilter { @Override final public boolean accept(File file) { if (!file.isFile()) return false; return file.getName().endsWith(".java"); } } CompilerStatus getStatus() { return new CompilerStatus(compilableMap, diagnosticMap, classPathSet); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy