/* * JBoss, Home of Professional Open Source * Copyright 2012, Red Hat Middleware LLC, and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * 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.jboss.shrinkwrap.resolver.impl.maven.archive.packaging; import java.io.File; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import org.codehaus.plexus.compiler.CompilerConfiguration; import org.codehaus.plexus.compiler.CompilerException; import org.codehaus.plexus.compiler.CompilerMessage; import org.codehaus.plexus.compiler.CompilerResult; import org.codehaus.plexus.compiler.javac.JavacCompiler; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.resolver.api.maven.MavenResolvedArtifact; import org.jboss.shrinkwrap.resolver.api.maven.MavenWorkingSession; import org.jboss.shrinkwrap.resolver.api.maven.ScopeType; import org.jboss.shrinkwrap.resolver.api.maven.archive.importer.MavenImporterException; import org.jboss.shrinkwrap.resolver.api.maven.strategy.AcceptScopesStrategy; import org.jboss.shrinkwrap.resolver.api.maven.strategy.MavenResolutionStrategy; import org.jboss.shrinkwrap.resolver.impl.maven.archive.plugins.CompilerPluginConfiguration; import org.jboss.shrinkwrap.resolver.impl.maven.task.AddScopedDependenciesTask; import org.jboss.shrinkwrap.resolver.impl.maven.util.Validate; import org.jboss.shrinkwrap.resolver.spi.maven.archive.packaging.PackagingProcessor; /** * Packaging processor which is able to compile Java sources * * @author <a href="mailto:kpiwko@redhat.com">Karel Piwko</a> * * @param <ARCHIVETYPE> Type of the archive produced */ public abstract class AbstractCompilingProcessor<ARCHIVETYPE extends Archive<ARCHIVETYPE>> implements PackagingProcessor<ARCHIVETYPE> { private static final Logger log = Logger.getLogger(AbstractCompilingProcessor.class.getName()); // this pattern is used to check whether archive name was autogenerated private static final Pattern UUID4_PATTERN = Pattern.compile("[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}\\.[a-z]+"); protected MavenWorkingSession session; protected PackagingProcessor<ARCHIVETYPE> configure(MavenWorkingSession session) { this.session = session; return this; } protected AbstractCompilingProcessor<ARCHIVETYPE> compile(File inputDirectory, File outputDirectory, ScopeType... scopes) { Validate.notNullAndNoNullValues(scopes, "Cannot compile sources, there were no scopes defined"); Validate.notNull(inputDirectory, "Directory with sources to be compiled must not be null"); Validate.notNull(outputDirectory, "Target directory for compiled sources must not be null"); JavacCompiler compiler = new JavacCompiler(); CompilerConfiguration configuration = getCompilerConfiguration(); if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "Compiling sources from {0} directory into {1}", new Object[] { inputDirectory, outputDirectory }); } // in order to compile sources, we need to resolve dependencies first // so we have a classpath available new AddScopedDependenciesTask(ScopeType.values()).execute(session); final MavenResolutionStrategy scopeStrategy = new AcceptScopesStrategy(scopes); final Collection<MavenResolvedArtifact> artifactResults = session.resolveDependencies(scopeStrategy); for (MavenResolvedArtifact artifact : artifactResults) { String classpathEntry = artifact.asFile().getAbsolutePath(); configuration.addClasspathEntry(classpathEntry); if (log.isLoggable(Level.FINER)) { log.log(Level.FINER, "Adding {0} to compilation classpath", classpathEntry); } } configuration.addSourceLocation(inputDirectory.getPath()); configuration.setOutputLocation(outputDirectory.getPath()); try { CompilerResult result = compiler.performCompile(configuration); if (!result.isSuccess()) { // try to fork compilation process if it wasn't set to fork already if (!configuration.isFork()) { log.log(Level.WARNING, "MavenImporter was not able to identify javac compiler, probably JAVA_HOME points to JRE instead of JDK. MavenImporter will try to fork and use javac from $PATH"); configuration.setFork(true); CompilerResult result2 = compiler.performCompile(configuration); if (!result2.isSuccess()) { log.log(Level.WARNING, "Unable to compile project with neither forked nor embedded compiler. Returning original exception message"); // throw original exception throw constructCompilationException(result, inputDirectory); } } else { throw constructCompilationException(result, inputDirectory); } } } catch (CompilerException e) { log.log(Level.SEVERE, "Compilation failed with {0}", e.getMessage()); throw new MavenImporterException("Unable to compile source at " + inputDirectory.getPath() + " due to: ", e); } return this; } private CompilerConfiguration getCompilerConfiguration() { CompilerPluginConfiguration pluginConfiguration = new CompilerPluginConfiguration(session.getParsedPomFile()); return pluginConfiguration.asCompilerConfiguration(); } protected static boolean hasGeneratedName(Archive<?> archive) { String archiveName = archive.getName(); return archiveName != null && UUID4_PATTERN.matcher(archiveName.toLowerCase()).matches(); } private static MavenImporterException constructCompilationException(CompilerResult result, File sourceDirectory) { StringBuilder sb = new StringBuilder("Unable to compile sources at "); sb.append(sourceDirectory.getPath()); sb.append(" due to following reason(s): "); String delimiter = ""; for (CompilerMessage m : result.getCompilerMessages()) { sb.append(delimiter).append(m.toString()); delimiter = ", "; } log.log(Level.SEVERE, sb.toString()); return new MavenImporterException(sb.toString()); } }