blob: 5b2685c18a53c2d6e02b013bedcc140c910ea0ae [file] [log] [blame]
/**
* This file is part of "Object Teams Development Tooling"-Software.
*
* Copyright 2013 GK Software AG.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Stephan Herrmann - Initial API and implementation.
*/
package org.eclipse.objectteams.weaver.plugin;
import java.io.File;
import java.io.FileWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.repository.RepositorySystem;
import org.eclipse.objectteams.builder.BuildTimeWeaver;
import org.eclipse.objectteams.builder.ILogger;
import org.eclipse.objectteams.builder.Requestor;
/**
* Mojo / Maven plug-in for performing OT/J byte code weaving during build time,
* rather than at load-time as the OTRE normally does.
* This serves as a fallback for running OT/J programs on platforms where
* class loading cannot be intercepted for load-time weaving.
* <p>
* <b>Configuration:</b> Clients using this plug-in configure the weaver
* using the following properties:
* <ul>
* <li>{@link #teamClasses}
* <li>{@link #activeTeamClasses}
* <li>{@link #mainClass}
* </ul>
*/
@Mojo(name="weave",defaultPhase=LifecyclePhase.PROCESS_CLASSES)
public class WeaverMojo extends AbstractMojo
{
private static final String OT_TEAMCONFIG_PROPERTY = "ot.teamconfig"; //$NON-NLS-1$
private static final String OT_TEAMCONFIG_FILENAME = "otteamconfig.txt"; //$NON-NLS-1$
private static final String MISSING_MAIN_CLASS_NAME_ERROR =
"Missing main class name. A main class is mandatory when activeTeamClasses are given";
// ======== Parameters for configuration via pom.xml: =========
/** List of all team classes to weave. */
@Parameter(required=true)
protected String[] teamClasses;
/**
* List of team classes ot instantiate and activate on program start,
* requires {@link #mainClass} to be set, too.
*/
@Parameter
protected String[] activeTeamClasses;
/**
* Main class, required if activation of teams should be woven,
* see {@link #activeTeamClasses}.
*/
@Parameter
protected String mainClass;
/**
* Where to place woven class files.
*/
@Parameter(defaultValue="target/woven-classes")
protected File wovenClassDirectory;
// ====== Parameters not meant for client configuration, simply access project context: =====
@Parameter(defaultValue="${project}")
private org.apache.maven.project.MavenProject mavenProject;
@Parameter(defaultValue="${localRepository}")
private org.apache.maven.artifact.repository.ArtifactRepository localRepository;
// ====== Dependency injection ======
@Component
private RepositorySystem repoSystem;
/**
* Main entry into this Mojo.
*/
public void execute()
throws MojoExecutionException, MojoFailureException
{
if (!wovenClassDirectory.exists())
wovenClassDirectory.mkdirs();
try {
ILogger logger = new ILogger() {
@Override public void info(String msg) { getLog().info(msg); }
@Override public void debug(String msg) { getLog().debug(msg); }
@Override public void error(String msg) { getLog().error(msg); }
};
BuildTimeWeaver weaver = new BuildTimeWeaver(logger);
if (activeTeamClasses != null && activeTeamClasses.length != 0) {
if (mainClass == null) {
getLog().error(MISSING_MAIN_CLASS_NAME_ERROR);
throw new MojoFailureException(MISSING_MAIN_CLASS_NAME_ERROR);
}
File configFile = new File(wovenClassDirectory, OT_TEAMCONFIG_FILENAME);
try (FileWriter fileWriter = new FileWriter(configFile)) {
for (String activeTeam : activeTeamClasses)
fileWriter.append(activeTeam+'\n');
}
System.setProperty(OT_TEAMCONFIG_PROPERTY, configFile.getAbsolutePath());
} else {
String configProperty = System.getProperty(OT_TEAMCONFIG_PROPERTY);
if (configProperty != null) {
throw new MojoFailureException("Property "+OT_TEAMCONFIG_PROPERTY+" is set to "+configProperty+" but cannot be used via Maven");
}
}
Requestor requestor = new Requestor(wovenClassDirectory.getAbsolutePath());
ClassLoader loader= getClassLoader();
weaver.weave(teamClasses, mainClass, loader, requestor);
} catch (MojoFailureException e) {
throw e;
} catch (Throwable e) {
throw new MojoExecutionException("Failed to weave classes", e);
}
}
private ClassLoader getClassLoader() throws MalformedURLException, DependencyResolutionRequiredException {
List<URL> urls = new ArrayList<URL>();
// collect URLs to load from:
// -- seems to correspond to project output folders:
for (Object object : mavenProject.getCompileClasspathElements()) {
urls.add(new File((String) object).toURI().toURL());
getLog().debug("WeaverMojo using classpath element "+object);
}
// -- reference all maven dependencies via the local repository:
for (Dependency dependency : mavenProject.getDependencies()) {
Artifact artifact = repoSystem.createDependencyArtifact(dependency);
String path = localRepository.getUrl()+localRepository.pathOf(artifact);
urls.add(new URL(path));
getLog().debug("WeaverMojo using dependency from "+path);
}
return new URLClassLoader(urls.toArray(new URL[] {}));
}
// ------------- currently unused: ---------------------
/**
* Recursively collect all .class files into 'result'
* @param root directory where searching starts
* @param currentPrefix either "" (root) or "some/prefix/", so that file names can be directly appended
* @param result accumulated list of all filenames found
*/
void listRecursive(File root, String currentPrefix, Set<String> result) {
File[] list = root.listFiles();
if (list == null) return;
for (File f : list ) {
if (f.isDirectory() )
listRecursive(f, currentPrefix+f.getName()+File.separator, result);
else if (f.getName().endsWith(".class"))
result.add((currentPrefix+f.getName()).replace('\\', '/'));
}
}
}